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;
15 import static org.openhab.binding.teleinfo.internal.TeleinfoBindingConstants.*;
17 import java.util.HashMap;
20 import java.util.stream.Collectors;
21 import java.util.stream.Stream;
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.openhab.binding.teleinfo.internal.dto.Frame;
26 import org.openhab.binding.teleinfo.internal.dto.cbemm.FrameCbemmBaseOption;
27 import org.openhab.binding.teleinfo.internal.dto.cbemm.FrameCbemmEjpOption;
28 import org.openhab.binding.teleinfo.internal.dto.cbemm.FrameCbemmHcOption;
29 import org.openhab.binding.teleinfo.internal.dto.cbemm.FrameCbemmTempoOption;
30 import org.openhab.binding.teleinfo.internal.dto.cbemm.evoicc.FrameCbemmEvolutionIccBaseOption;
31 import org.openhab.binding.teleinfo.internal.dto.cbemm.evoicc.FrameCbemmEvolutionIccEjpOption;
32 import org.openhab.binding.teleinfo.internal.dto.cbemm.evoicc.FrameCbemmEvolutionIccHcOption;
33 import org.openhab.binding.teleinfo.internal.dto.cbemm.evoicc.FrameCbemmEvolutionIccTempoOption;
34 import org.openhab.binding.teleinfo.internal.dto.cbetm.FrameCbetmLongBaseOption;
35 import org.openhab.binding.teleinfo.internal.dto.cbetm.FrameCbetmLongEjpOption;
36 import org.openhab.binding.teleinfo.internal.dto.cbetm.FrameCbetmLongHcOption;
37 import org.openhab.binding.teleinfo.internal.dto.cbetm.FrameCbetmLongTempoOption;
38 import org.openhab.binding.teleinfo.internal.dto.common.FrameAdco;
39 import org.openhab.binding.teleinfo.internal.handler.TeleinfoAbstractControllerHandler;
40 import org.openhab.binding.teleinfo.internal.handler.TeleinfoControllerHandlerListener;
41 import org.openhab.core.config.discovery.AbstractDiscoveryService;
42 import org.openhab.core.config.discovery.DiscoveryResult;
43 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
44 import org.openhab.core.config.discovery.DiscoveryService;
45 import org.openhab.core.thing.ThingTypeUID;
46 import org.openhab.core.thing.ThingUID;
47 import org.openhab.core.thing.binding.ThingHandler;
48 import org.openhab.core.thing.binding.ThingHandlerService;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
53 * The {@link TeleinfoDiscoveryService} class is the service to discover a skeleton for controller handlers.
55 * @author Nicolas SIBERIL - Initial contribution
58 public class TeleinfoDiscoveryService extends AbstractDiscoveryService
59 implements TeleinfoControllerHandlerListener, ThingHandlerService, DiscoveryService {
61 private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream.of(THING_HC_CBEMM_ELECTRICITY_METER_TYPE_UID,
62 THING_BASE_CBEMM_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBEMM_ELECTRICITY_METER_TYPE_UID,
63 THING_EJP_CBEMM_ELECTRICITY_METER_TYPE_UID, THING_HC_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID,
64 THING_BASE_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID,
65 THING_EJP_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID, THING_HC_CBETM_ELECTRICITY_METER_TYPE_UID,
66 THING_BASE_CBETM_ELECTRICITY_METER_TYPE_UID, THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID,
67 THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID).collect(Collectors.toSet());
69 private static final int SCAN_DURATION_IN_S = 60;
71 private final Logger logger = LoggerFactory.getLogger(TeleinfoDiscoveryService.class);
72 private @Nullable TeleinfoAbstractControllerHandler controllerHandler;
74 public TeleinfoDiscoveryService() {
75 super(SCAN_DURATION_IN_S);
78 public TeleinfoDiscoveryService(TeleinfoAbstractControllerHandler controllerHandler) {
79 super(SCAN_DURATION_IN_S);
80 this.controllerHandler = controllerHandler;
84 public Set<ThingTypeUID> getSupportedThingTypes() {
85 return SUPPORTED_THING_TYPES;
88 public void activate() {
89 TeleinfoAbstractControllerHandler controllerHandlerRef = controllerHandler;
90 if (controllerHandlerRef != null) {
91 logger.debug("Teleinfo discovery: Activate {}", controllerHandlerRef.getThing().getUID());
93 logNullControllerHandler();
98 public void deactivate() {
99 TeleinfoAbstractControllerHandler controllerHandlerRef = controllerHandler;
100 if (controllerHandlerRef != null) {
101 logger.debug("Teleinfo discovery: Deactivate {}", controllerHandlerRef.getThing().getUID());
103 logNullControllerHandler();
108 protected void startScan() {
109 TeleinfoAbstractControllerHandler controllerHandlerRef = controllerHandler;
110 if (controllerHandlerRef != null) {
111 logger.debug("Teleinfo discovery: Start {}", controllerHandlerRef.getThing().getUID());
113 // Start the search for new devices
114 controllerHandlerRef.addListener(this);
116 logNullControllerHandler();
121 public synchronized void abortScan() {
122 TeleinfoAbstractControllerHandler controllerHandlerRef = controllerHandler;
123 if (controllerHandlerRef != null) {
124 logger.debug("Teleinfo discovery: Abort {}", controllerHandlerRef.getThing().getUID());
125 controllerHandlerRef.removeListener(this);
128 logNullControllerHandler();
133 protected synchronized void stopScan() {
134 TeleinfoAbstractControllerHandler controllerHandlerRef = controllerHandler;
135 if (controllerHandlerRef != null) {
136 logger.debug("Teleinfo discovery: Stop {}", controllerHandlerRef.getThing().getUID());
137 controllerHandlerRef.removeListener(this);
140 logNullControllerHandler();
145 public void onFrameReceived(TeleinfoAbstractControllerHandler controllerHandler, Frame frame) {
146 detectNewElectricityMeterFromReceivedFrame(frame);
149 private void detectNewElectricityMeterFromReceivedFrame(final Frame frameSample) {
150 TeleinfoAbstractControllerHandler controllerHandlerRef = controllerHandler;
151 if (controllerHandlerRef != null) {
152 logger.debug("New eletricity meter detection from frame {}", frameSample.getId());
153 if (!(frameSample instanceof FrameAdco)) {
154 throw new IllegalStateException("Teleinfo frame type not supported: " + frameSample.getClass());
156 final FrameAdco frameAdco = (FrameAdco) frameSample;
158 ThingUID thingUID = new ThingUID(getThingTypeUID(frameAdco), frameAdco.getAdco(),
159 controllerHandlerRef.getThing().getUID().getId());
161 final Map<String, Object> properties = getThingProperties(frameAdco);
162 final String representationProperty = THING_ELECTRICITY_METER_PROPERTY_ADCO;
163 DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
164 .withLabel("Teleinfo ADCO " + frameAdco.getAdco()).withThingType(getThingTypeUID(frameAdco))
165 .withBridge(controllerHandlerRef.getThing().getUID())
166 .withRepresentationProperty(representationProperty).build();
168 thingDiscovered(discoveryResult);
170 logNullControllerHandler();
174 private ThingTypeUID getThingTypeUID(final Frame teleinfoFrame) {
175 if (teleinfoFrame instanceof FrameCbemmHcOption) {
176 return THING_HC_CBEMM_ELECTRICITY_METER_TYPE_UID;
177 } else if (teleinfoFrame instanceof FrameCbemmBaseOption) {
178 return THING_BASE_CBEMM_ELECTRICITY_METER_TYPE_UID;
179 } else if (teleinfoFrame instanceof FrameCbemmEjpOption) {
180 return THING_EJP_CBEMM_ELECTRICITY_METER_TYPE_UID;
181 } else if (teleinfoFrame instanceof FrameCbemmTempoOption) {
182 return THING_TEMPO_CBEMM_ELECTRICITY_METER_TYPE_UID;
183 } else if (teleinfoFrame instanceof FrameCbemmEvolutionIccHcOption) {
184 return THING_HC_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID;
185 } else if (teleinfoFrame instanceof FrameCbemmEvolutionIccBaseOption) {
186 return THING_BASE_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID;
187 } else if (teleinfoFrame instanceof FrameCbemmEvolutionIccEjpOption) {
188 return THING_EJP_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID;
189 } else if (teleinfoFrame instanceof FrameCbemmEvolutionIccTempoOption) {
190 return THING_TEMPO_CBEMM_EVO_ICC_ELECTRICITY_METER_TYPE_UID;
191 } else if (teleinfoFrame instanceof FrameCbetmLongHcOption) {
192 return THING_HC_CBETM_ELECTRICITY_METER_TYPE_UID;
193 } else if (teleinfoFrame instanceof FrameCbetmLongBaseOption) {
194 return THING_BASE_CBETM_ELECTRICITY_METER_TYPE_UID;
195 } else if (teleinfoFrame instanceof FrameCbetmLongEjpOption) {
196 return THING_EJP_CBETM_ELECTRICITY_METER_TYPE_UID;
197 } else if (teleinfoFrame instanceof FrameCbetmLongTempoOption) {
198 return THING_TEMPO_CBETM_ELECTRICITY_METER_TYPE_UID;
200 throw new IllegalStateException("Teleinfo frame type not supported: " + teleinfoFrame.getClass());
204 private Map<String, Object> getThingProperties(final Frame teleinfoFrame) {
205 Map<String, Object> properties = new HashMap<String, Object>();
206 if (teleinfoFrame instanceof FrameAdco) {
207 final FrameAdco frameAdco = (FrameAdco) teleinfoFrame;
208 properties.put(THING_ELECTRICITY_METER_PROPERTY_ADCO, frameAdco.getAdco());
213 throw new IllegalStateException("Teleinfo frame type not supported: " + teleinfoFrame.getClass());
217 public void setThingHandler(@Nullable ThingHandler handler) {
218 if (handler instanceof TeleinfoAbstractControllerHandler) {
219 controllerHandler = (TeleinfoAbstractControllerHandler) handler;
224 public @Nullable ThingHandler getThingHandler() {
225 return controllerHandler;
228 private void logNullControllerHandler() {
229 logger.warn("Null controller handler");