2 * Copyright (c) 2010-2024 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.smaenergymeter.internal.handler;
15 import java.io.IOException;
16 import java.nio.ByteBuffer;
17 import java.util.Arrays;
19 import org.openhab.core.library.types.DecimalType;
22 * The {@link EnergyMeter} class is responsible for communication with the SMA device
23 * and extracting the data fields out of the received telegrams.
25 * @author Osman Basha - Initial contribution
26 * @author Ćukasz Dywicki - Extracted multicast group handling to
27 * {@link org.openhab.binding.smaenergymeter.internal.packet.PacketListener}.
29 public class EnergyMeter {
31 private static final byte[] E_METER_PROTOCOL_ID = new byte[] { 0x60, 0x69 };
33 private String serialNumber;
34 private final FieldDTO powerIn;
35 private final FieldDTO energyIn;
36 private final FieldDTO powerOut;
37 private final FieldDTO energyOut;
38 private final FieldDTO powerInL1;
39 private final FieldDTO energyInL1;
40 private final FieldDTO powerOutL1;
41 private final FieldDTO energyOutL1;
42 private final FieldDTO powerInL2;
43 private final FieldDTO energyInL2;
44 private final FieldDTO powerOutL2;
45 private final FieldDTO energyOutL2;
46 private final FieldDTO powerInL3;
47 private final FieldDTO energyInL3;
48 private final FieldDTO powerOutL3;
49 private final FieldDTO energyOutL3;
51 public EnergyMeter() {
52 powerIn = new FieldDTO(0x20, 4, 10);
53 energyIn = new FieldDTO(0x28, 8, 3600000);
54 powerOut = new FieldDTO(0x34, 4, 10);
55 energyOut = new FieldDTO(0x3C, 8, 3600000);
57 powerInL1 = new FieldDTO(0xA8, 4, 10);
58 energyInL1 = new FieldDTO(0xB0, 8, 3600000); // +8
59 powerOutL1 = new FieldDTO(0xBC, 4, 10); // + C
60 energyOutL1 = new FieldDTO(0xC4, 8, 3600000); // +8
62 powerInL2 = new FieldDTO(0x138, 4, 10);
63 energyInL2 = new FieldDTO(0x140, 8, 3600000); // +8
64 powerOutL2 = new FieldDTO(0x14C, 4, 10); // + C
65 energyOutL2 = new FieldDTO(0x154, 8, 3600000); // +8
67 powerInL3 = new FieldDTO(0x1C8, 4, 10);
68 energyInL3 = new FieldDTO(0x1D0, 8, 3600000); // +8
69 powerOutL3 = new FieldDTO(0x1DC, 4, 10); // + C
70 energyOutL3 = new FieldDTO(0x1E4, 8, 3600000); // +8
73 public void parse(byte[] bytes) throws IOException {
75 String sma = new String(Arrays.copyOfRange(bytes, 0, 3));
76 if (!"SMA".equals(sma)) {
77 throw new IOException("Not a SMA telegram." + sma);
79 byte[] protocolId = Arrays.copyOfRange(bytes, 16, 18);
80 if (!Arrays.equals(protocolId, E_METER_PROTOCOL_ID)) {
81 throw new IllegalArgumentException(
82 "Received frame with wrong protocol ID " + Arrays.toString(protocolId));
85 ByteBuffer buffer = ByteBuffer.wrap(Arrays.copyOfRange(bytes, 0x14, 0x18));
86 serialNumber = Integer.toHexString(buffer.getInt());
88 powerIn.updateValue(bytes);
89 energyIn.updateValue(bytes);
90 powerOut.updateValue(bytes);
91 energyOut.updateValue(bytes);
93 powerInL1.updateValue(bytes);
94 energyInL1.updateValue(bytes);
95 powerOutL1.updateValue(bytes);
96 energyOutL1.updateValue(bytes);
98 powerInL2.updateValue(bytes);
99 energyInL2.updateValue(bytes);
100 powerOutL2.updateValue(bytes);
101 energyOutL2.updateValue(bytes);
103 powerInL3.updateValue(bytes);
104 energyInL3.updateValue(bytes);
105 powerOutL3.updateValue(bytes);
106 energyOutL3.updateValue(bytes);
107 } catch (Exception e) {
108 throw new IOException(e);
112 public String getSerialNumber() {
116 public DecimalType getPowerIn() {
117 return new DecimalType(powerIn.getValue());
120 public DecimalType getPowerOut() {
121 return new DecimalType(powerOut.getValue());
124 public DecimalType getEnergyIn() {
125 return new DecimalType(energyIn.getValue());
128 public DecimalType getEnergyOut() {
129 return new DecimalType(energyOut.getValue());
132 public DecimalType getPowerInL1() {
133 return new DecimalType(powerInL1.getValue());
136 public DecimalType getPowerOutL1() {
137 return new DecimalType(powerOutL1.getValue());
140 public DecimalType getEnergyInL1() {
141 return new DecimalType(energyInL1.getValue());
144 public DecimalType getEnergyOutL1() {
145 return new DecimalType(energyOutL1.getValue());
148 public DecimalType getPowerInL2() {
149 return new DecimalType(powerInL2.getValue());
152 public DecimalType getPowerOutL2() {
153 return new DecimalType(powerOutL2.getValue());
156 public DecimalType getEnergyInL2() {
157 return new DecimalType(energyInL2.getValue());
160 public DecimalType getEnergyOutL2() {
161 return new DecimalType(energyOutL2.getValue());
164 public DecimalType getPowerInL3() {
165 return new DecimalType(powerInL3.getValue());
168 public DecimalType getPowerOutL3() {
169 return new DecimalType(powerOutL3.getValue());
172 public DecimalType getEnergyInL3() {
173 return new DecimalType(energyInL3.getValue());
176 public DecimalType getEnergyOutL3() {
177 return new DecimalType(energyOutL3.getValue());