2 * Copyright (c) 2010-2023 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.net.DatagramPacket;
17 import java.net.InetAddress;
18 import java.net.MulticastSocket;
19 import java.nio.ByteBuffer;
20 import java.util.Arrays;
21 import java.util.Date;
23 import org.openhab.core.library.types.DecimalType;
26 * The {@link EnergyMeter} class is responsible for communication with the SMA device
27 * and extracting the data fields out of the received telegrams.
29 * @author Osman Basha - Initial contribution
31 public class EnergyMeter {
33 private String multicastGroup;
36 private String serialNumber;
37 private Date lastUpdate;
39 private final FieldDTO powerIn;
40 private final FieldDTO energyIn;
41 private final FieldDTO powerOut;
42 private final FieldDTO energyOut;
43 private final FieldDTO powerInL1;
44 private final FieldDTO energyInL1;
45 private final FieldDTO powerOutL1;
46 private final FieldDTO energyOutL1;
47 private final FieldDTO powerInL2;
48 private final FieldDTO energyInL2;
49 private final FieldDTO powerOutL2;
50 private final FieldDTO energyOutL2;
51 private final FieldDTO powerInL3;
52 private final FieldDTO energyInL3;
53 private final FieldDTO powerOutL3;
54 private final FieldDTO energyOutL3;
56 public static final String DEFAULT_MCAST_GRP = "239.12.255.254";
57 public static final int DEFAULT_MCAST_PORT = 9522;
59 public EnergyMeter(String multicastGroup, int port) {
60 this.multicastGroup = multicastGroup;
63 powerIn = new FieldDTO(0x20, 4, 10);
64 energyIn = new FieldDTO(0x28, 8, 3600000);
65 powerOut = new FieldDTO(0x34, 4, 10);
66 energyOut = new FieldDTO(0x3C, 8, 3600000);
68 powerInL1 = new FieldDTO(0xA8, 4, 10);
69 energyInL1 = new FieldDTO(0xB0, 8, 3600000); // +8
70 powerOutL1 = new FieldDTO(0xBC, 4, 10); // + C
71 energyOutL1 = new FieldDTO(0xC4, 8, 3600000); // +8
73 powerInL2 = new FieldDTO(0x138, 4, 10);
74 energyInL2 = new FieldDTO(0x140, 8, 3600000); // +8
75 powerOutL2 = new FieldDTO(0x14C, 4, 10); // + C
76 energyOutL2 = new FieldDTO(0x154, 8, 3600000); // +8
78 powerInL3 = new FieldDTO(0x1C8, 4, 10);
79 energyInL3 = new FieldDTO(0x1D0, 8, 3600000); // +8
80 powerOutL3 = new FieldDTO(0x1DC, 4, 10); // + C
81 energyOutL3 = new FieldDTO(0x1E4, 8, 3600000); // +8
84 public void update() throws IOException {
85 byte[] bytes = new byte[608];
86 try (MulticastSocket socket = new MulticastSocket(port)) {
87 socket.setSoTimeout(5000);
88 InetAddress address = InetAddress.getByName(multicastGroup);
89 socket.joinGroup(address);
91 DatagramPacket msgPacket = new DatagramPacket(bytes, bytes.length);
92 socket.receive(msgPacket);
94 String sma = new String(Arrays.copyOfRange(bytes, 0x00, 0x03));
95 if (!sma.equals("SMA")) {
96 throw new IOException("Not a SMA telegram." + sma);
99 ByteBuffer buffer = ByteBuffer.wrap(Arrays.copyOfRange(bytes, 0x14, 0x18));
100 serialNumber = String.valueOf(buffer.getInt());
102 powerIn.updateValue(bytes);
103 energyIn.updateValue(bytes);
104 powerOut.updateValue(bytes);
105 energyOut.updateValue(bytes);
107 powerInL1.updateValue(bytes);
108 energyInL1.updateValue(bytes);
109 powerOutL1.updateValue(bytes);
110 energyOutL1.updateValue(bytes);
112 powerInL2.updateValue(bytes);
113 energyInL2.updateValue(bytes);
114 powerOutL2.updateValue(bytes);
115 energyOutL2.updateValue(bytes);
117 powerInL3.updateValue(bytes);
118 energyInL3.updateValue(bytes);
119 powerOutL3.updateValue(bytes);
120 energyOutL3.updateValue(bytes);
122 lastUpdate = new Date(System.currentTimeMillis());
123 } catch (Exception e) {
124 throw new IOException(e);
128 public String getSerialNumber() {
132 public Date getLastUpdate() {
136 public DecimalType getPowerIn() {
137 return new DecimalType(powerIn.getValue());
140 public DecimalType getPowerOut() {
141 return new DecimalType(powerOut.getValue());
144 public DecimalType getEnergyIn() {
145 return new DecimalType(energyIn.getValue());
148 public DecimalType getEnergyOut() {
149 return new DecimalType(energyOut.getValue());
152 public DecimalType getPowerInL1() {
153 return new DecimalType(powerInL1.getValue());
156 public DecimalType getPowerOutL1() {
157 return new DecimalType(powerOutL1.getValue());
160 public DecimalType getEnergyInL1() {
161 return new DecimalType(energyInL1.getValue());
164 public DecimalType getEnergyOutL1() {
165 return new DecimalType(energyOutL1.getValue());
168 public DecimalType getPowerInL2() {
169 return new DecimalType(powerInL2.getValue());
172 public DecimalType getPowerOutL2() {
173 return new DecimalType(powerOutL2.getValue());
176 public DecimalType getEnergyInL2() {
177 return new DecimalType(energyInL2.getValue());
180 public DecimalType getEnergyOutL2() {
181 return new DecimalType(energyOutL2.getValue());
184 public DecimalType getPowerInL3() {
185 return new DecimalType(powerInL3.getValue());
188 public DecimalType getPowerOutL3() {
189 return new DecimalType(powerOutL3.getValue());
192 public DecimalType getEnergyInL3() {
193 return new DecimalType(energyInL3.getValue());
196 public DecimalType getEnergyOutL3() {
197 return new DecimalType(energyOutL3.getValue());