2 * Copyright (c) 2010-2021 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.teleinfo.internal.handler;
15 import static org.openhab.binding.teleinfo.internal.TeleinfoBindingConstants.*;
17 import java.util.Map.Entry;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.teleinfo.internal.data.Frame;
22 import org.openhab.binding.teleinfo.internal.data.Phase;
23 import org.openhab.binding.teleinfo.internal.data.Pricing;
24 import org.openhab.binding.teleinfo.internal.reader.io.serialport.InvalidFrameException;
25 import org.openhab.binding.teleinfo.internal.reader.io.serialport.Label;
26 import org.openhab.binding.teleinfo.internal.reader.io.serialport.ValueType;
27 import org.openhab.core.library.types.DateTimeType;
28 import org.openhab.core.library.types.QuantityType;
29 import org.openhab.core.library.types.StringType;
30 import org.openhab.core.thing.Bridge;
31 import org.openhab.core.thing.Channel;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.ThingStatusInfo;
37 import org.openhab.core.thing.binding.BaseThingHandler;
38 import org.openhab.core.types.Command;
39 import org.openhab.core.types.UnDefType;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
44 * The {@link TeleinfoElectricityMeterHandler} class defines a skeleton for Electricity Meters handlers.
46 * @author Nicolas SIBERIL - Initial contribution
49 public class TeleinfoElectricityMeterHandler extends BaseThingHandler implements TeleinfoControllerHandlerListener {
51 private final Logger logger = LoggerFactory.getLogger(TeleinfoElectricityMeterHandler.class);
52 protected TeleinfoElectricityMeterConfiguration configuration = new TeleinfoElectricityMeterConfiguration();
53 private boolean wasLastFrameShort = false;
55 public TeleinfoElectricityMeterHandler(Thing thing) {
60 public void initialize() {
61 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, ERROR_OFFLINE_CONTROLLER_OFFLINE);
63 Bridge bridge = getBridge();
64 logger.debug("bridge = {}", bridge);
66 bridgeStatusChanged(bridge.getStatusInfo());
68 configuration = getConfigAs(TeleinfoElectricityMeterConfiguration.class);
72 public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
73 TeleinfoAbstractControllerHandler controllerHandler = getControllerHandler();
74 if (bridgeStatusInfo.getStatus() != ThingStatus.ONLINE) {
75 if (controllerHandler != null) {
76 controllerHandler.removeListener(this);
78 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, ERROR_OFFLINE_CONTROLLER_OFFLINE);
82 if (controllerHandler != null) {
83 controllerHandler.addListener(this);
84 updateStatus(ThingStatus.ONLINE);
89 public void dispose() {
90 TeleinfoAbstractControllerHandler controllerHandler = getControllerHandler();
91 if (controllerHandler != null) {
92 controllerHandler.removeListener(this);
97 private @Nullable TeleinfoAbstractControllerHandler getControllerHandler() {
98 Bridge bridge = getBridge();
99 return bridge != null ? (TeleinfoAbstractControllerHandler) bridge.getHandler() : null;
103 public void handleCommand(ChannelUID channelUID, Command command) {
104 // no commands supported
108 protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, @Nullable String description) {
109 super.updateStatus(status, statusDetail, description);
111 if (!(ThingStatus.ONLINE.equals(status))) {
112 for (Channel channel : getThing().getChannels()) {
113 if (!CHANNEL_LAST_UPDATE.equals(channel.getUID().getId())) {
114 updateState(channel.getUID(), UnDefType.UNDEF);
121 protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail) {
122 this.updateStatus(status, statusDetail, null);
126 protected void updateStatus(ThingStatus status) {
127 this.updateStatus(status, ThingStatusDetail.NONE, null);
131 public void onFrameReceived(Frame frame) {
132 String adco = configuration.getAdco();
133 if (adco.equalsIgnoreCase(frame.get(Label.ADCO))) {
134 updateStatesForChannels(frame);
138 private void updateStatesForChannels(Frame frame) {
139 for (Entry<Label, String> entry : frame.getLabelToValues().entrySet()) {
140 Label label = entry.getKey();
141 if (!label.getChannelName().equals(NOT_A_CHANNEL)) {
142 if (label == Label.PTEC) {
143 updateState(label.getChannelName(), StringType.valueOf(entry.getValue().replace(".", "")));
144 } else if (label.getType() == ValueType.STRING) {
145 updateState(label.getChannelName(), StringType.valueOf(entry.getValue()));
146 } else if (label.getType() == ValueType.INTEGER) {
147 updateState(label.getChannelName(),
148 QuantityType.valueOf(Integer.parseInt(entry.getValue()), label.getUnit()));
153 if (frame.getPricing() == Pricing.TEMPO) {
154 updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_1, StringType.valueOf(frame.getProgrammeCircuit1()));
155 updateState(CHANNEL_TEMPO_FRAME_PROGRAMME_CIRCUIT_2, StringType.valueOf(frame.getProgrammeCircuit2()));
157 } catch (InvalidFrameException e) {
158 logger.warn("Can not find pricing option.");
162 Phase phase = frame.getPhase();
163 if (phase == Phase.ONE_PHASED) {
164 updateStateForMissingAlert(frame, Label.ADPS);
165 } else if (phase == Phase.THREE_PHASED) {
166 if (!wasLastFrameShort) {
167 updateStateForMissingAlert(frame, Label.ADIR1);
168 updateStateForMissingAlert(frame, Label.ADIR2);
169 updateStateForMissingAlert(frame, Label.ADIR3);
171 wasLastFrameShort = frame.isShortFrame();
173 } catch (InvalidFrameException e) {
174 logger.warn("Can not find phase.");
177 updateState(CHANNEL_LAST_UPDATE, new DateTimeType());
180 private void updateStateForMissingAlert(Frame frame, Label label) {
181 if (!frame.getLabelToValues().containsKey(label)) {
182 updateState(label.getChannelName(), UnDefType.NULL);