2 * Copyright (c) 2010-2022 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.dsmr.internal.discovery;
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.Mockito.when;
17 import static org.openhab.binding.dsmr.internal.meter.DSMRMeterType.*;
19 import java.util.Collections;
20 import java.util.EnumSet;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.concurrent.atomic.AtomicBoolean;
24 import java.util.concurrent.atomic.AtomicReference;
25 import java.util.stream.Collectors;
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.junit.jupiter.api.Test;
29 import org.junit.jupiter.api.extension.ExtendWith;
30 import org.mockito.Answers;
31 import org.mockito.Mock;
32 import org.mockito.junit.jupiter.MockitoExtension;
33 import org.openhab.binding.dsmr.internal.TelegramReaderUtil;
34 import org.openhab.binding.dsmr.internal.device.p1telegram.P1Telegram;
35 import org.openhab.binding.dsmr.internal.device.p1telegram.P1Telegram.TelegramState;
36 import org.openhab.binding.dsmr.internal.handler.DSMRBridgeHandler;
37 import org.openhab.binding.dsmr.internal.handler.DSMRMeterHandler;
38 import org.openhab.binding.dsmr.internal.meter.DSMRMeterDescriptor;
39 import org.openhab.binding.dsmr.internal.meter.DSMRMeterType;
40 import org.openhab.core.thing.Thing;
41 import org.openhab.core.thing.ThingUID;
44 * Test class for {@link DSMRMeterDiscoveryService}.
46 * @author Hilbrand Bouwkamp - Initial contribution
48 @ExtendWith(MockitoExtension.class)
50 public class DSMRMeterDiscoveryServiceTest {
52 private static final String EXPECTED_CONFIGURED_TELEGRAM = "dsmr_50";
53 private static final String UNREGISTERED_METER_TELEGRAM = "unregistered_meter";
55 private @NonNullByDefault({}) @Mock(answer = Answers.RETURNS_DEEP_STUBS) DSMRBridgeHandler bridge;
56 private @NonNullByDefault({}) @Mock Thing thing;
57 private @NonNullByDefault({}) @Mock DSMRMeterHandler meterHandler;
60 * Test if discovery reports when the user has incorrectly configured the binding with the wrong meter types.
61 * Some meters are a subset of other meters so it won't generates errors in usage, but some values will not be
62 * available to the user with the subset meter.
65 public void testInvalidConfiguredMeters() {
66 P1Telegram expected = TelegramReaderUtil.readTelegram(EXPECTED_CONFIGURED_TELEGRAM, TelegramState.OK);
67 AtomicReference<List<DSMRMeterType>> invalidConfiguredRef = new AtomicReference<>();
68 AtomicReference<List<DSMRMeterType>> unconfiguredRef = new AtomicReference<>();
69 DSMRMeterDiscoveryService service = new DSMRMeterDiscoveryService() {
71 protected void reportConfigurationValidationResults(List<DSMRMeterType> invalidConfigured,
72 List<DSMRMeterType> unconfiguredMeters) {
73 super.reportConfigurationValidationResults(invalidConfigured, unconfiguredMeters);
74 invalidConfiguredRef.set(invalidConfigured);
75 unconfiguredRef.set(unconfiguredMeters);
78 service.setThingHandler(bridge);
80 // Mock the invalid configuration by reading a telegram that is valid for a meter that is a subset of the
82 List<DSMRMeterDescriptor> invalidConfiguredMeterDescriptors = EnumSet.of(DEVICE_V5, ELECTRICITY_V4_2, M3_V5_0)
83 .stream().map(mt -> new DSMRMeterDescriptor(mt, 0)).collect(Collectors.toList());
84 List<Thing> things = invalidConfiguredMeterDescriptors.stream().map(m -> thing).collect(Collectors.toList());
85 AtomicReference<Iterator<DSMRMeterDescriptor>> detectMetersRef = new AtomicReference<>();
86 when((meterHandler).getMeterDescriptor()).then(a -> {
87 if (detectMetersRef.get() == null || !detectMetersRef.get().hasNext()) {
88 detectMetersRef.set(invalidConfiguredMeterDescriptors.iterator());
90 return detectMetersRef.get().next();
92 when(thing.getHandler()).thenReturn(meterHandler);
93 when(bridge.getThing().getUID()).thenReturn(new ThingUID("dsmr:dsmrBridge:22e5393c"));
94 when(bridge.getThing().getThings()).thenReturn(things);
96 service.telegramReceived(expected);
97 assertNotNull(invalidConfiguredRef.get(), "Should have invalid configured meters");
98 assertTrue(invalidConfiguredRef.get().contains(DSMRMeterType.ELECTRICITY_V4_2),
99 "Should have found specific invalid meter");
100 assertNotNull(unconfiguredRef.get(), "Should have undetected meters");
101 assertTrue(unconfiguredRef.get().contains(DSMRMeterType.ELECTRICITY_V5_0),
102 "Should have found specific undetected meter");
106 * Test if discovery correctly reports if a meter was detected that has not been registered with the energy
107 * provider. This meter doesn't report all values in telegram and therefore is not recognized as a specific
108 * meter. But reports with an empty equipment identifier.
111 public void testUnregisteredMeters() {
112 P1Telegram telegram = TelegramReaderUtil.readTelegram(UNREGISTERED_METER_TELEGRAM, TelegramState.OK);
113 AtomicBoolean unregisteredMeter = new AtomicBoolean(false);
114 DSMRMeterDiscoveryService service = new DSMRMeterDiscoveryService() {
116 protected void reportUnregisteredMeters() {
117 super.reportUnregisteredMeters();
118 unregisteredMeter.set(true);
121 service.setThingHandler(bridge);
122 when(bridge.getThing().getUID()).thenReturn(new ThingUID("dsmr:dsmrBridge:22e5393c"));
123 when(bridge.getThing().getThings()).thenReturn(Collections.emptyList());
125 service.telegramReceived(telegram);
126 assertTrue(unregisteredMeter.get(), "Should have found an unregistered meter");