2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.nibeheatpump.internal.message;
15 import java.util.ArrayList;
16 import java.util.List;
18 import org.openhab.binding.nibeheatpump.internal.NibeHeatPumpException;
19 import org.openhab.binding.nibeheatpump.internal.protocol.NibeHeatPumpProtocol;
22 * The {@link ModbusDataReadOutMessage} implements Nibe data read out message.
24 * @author Pauli Anttila - Initial contribution
26 public class ModbusDataReadOutMessage extends NibeHeatPumpBaseMessage {
28 private List<ModbusValue> values;
30 private ModbusDataReadOutMessage(MessageBuilder builder) {
31 super.msgType = MessageType.MODBUS_DATA_READ_OUT_MSG;
32 this.values = builder.values;
35 public ModbusDataReadOutMessage(byte[] data) throws NibeHeatPumpException {
39 public List<ModbusValue> getValues() {
44 public void encodeMessage(byte[] data) throws NibeHeatPumpException {
45 values = parseMessage(data);
49 public byte[] decodeMessage() {
50 return createDataReadOutPdu(values);
53 private byte[] createDataReadOutPdu(List<ModbusValue> values) {
54 byte datalen = (byte) (values.size() * 4);
55 byte msglen = (byte) (6 + datalen);
57 byte[] data = new byte[msglen];
59 data[0] = NibeHeatPumpProtocol.FRAME_START_CHAR_FROM_NIBE;
61 data[2] = NibeHeatPumpProtocol.ADR_MODBUS40;
62 data[3] = NibeHeatPumpProtocol.CMD_MODBUS_DATA_MSG;
65 int i = NibeHeatPumpProtocol.OFFSET_DATA;
67 for (ModbusValue value : values) {
69 int coildAddress = value.getCoilAddress();
70 int val = value.getValue();
72 data[i + 0] = (byte) (coildAddress & 0xFF);
73 data[i + 1] = (byte) ((coildAddress >> 8) & 0xFF);
74 data[i + 2] = (byte) (val & 0xFF);
75 data[i + 3] = (byte) ((val >> 8) & 0xFF);
79 data[msglen - 1] = NibeHeatPumpProtocol.calculateChecksum(data, 2, msglen);
85 public String toString() {
86 String str = super.toString();
88 str += values.toString();
92 private List<ModbusValue> parseMessage(byte[] data) throws NibeHeatPumpException {
93 if (NibeHeatPumpProtocol.isModbus40DataReadOut(data)) {
94 super.encodeMessage(data);
95 final int msglen = 5 + rawMessage[NibeHeatPumpProtocol.OFFSET_LEN];
97 List<ModbusValue> vals = new ArrayList<>();
100 for (int i = NibeHeatPumpProtocol.OFFSET_DATA; i < (msglen - 1); i += 4) {
102 int id = ((rawMessage[i + 1] & 0xFF) << 8 | (rawMessage[i + 0] & 0xFF));
103 int value = (rawMessage[i + 3] & 0xFF) << 8 | (rawMessage[i + 2] & 0xFF);
106 vals.add(new ModbusValue(id, value));
109 } catch (ArrayIndexOutOfBoundsException e) {
110 throw new NibeHeatPumpException("Error occurred during data parsing", e);
116 throw new NibeHeatPumpException("Not Modbus data readout message");
120 public static class MessageBuilder {
121 private List<ModbusValue> values = new ArrayList<>();
123 public MessageBuilder values(List<ModbusValue> values) {
124 this.values = values;
128 public MessageBuilder value(ModbusValue value) {
129 this.values.add(value);
133 public MessageBuilder value(int coilAddress, int value) {
134 this.values.add(new ModbusValue(coilAddress, value));
138 public ModbusDataReadOutMessage build() {
139 return new ModbusDataReadOutMessage(this);