]> git.basschouten.com Git - openhab-addons.git/blob
911f7cc9ba4f983ef55989b7a2d891816e6811e4
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.hdpowerview.internal.gen3;
14
15 import static org.junit.jupiter.api.Assertions.*;
16 import static org.mockito.Mockito.mock;
17 import static org.openhab.binding.hdpowerview.internal.HDPowerViewBindingConstants.*;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.nio.charset.StandardCharsets;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Set;
25
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.junit.jupiter.api.Test;
28 import org.openhab.binding.hdpowerview.internal.HDPowerViewJUnitTests;
29 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase;
30 import org.openhab.binding.hdpowerview.internal.database.ShadeCapabilitiesDatabase.Capabilities;
31 import org.openhab.binding.hdpowerview.internal.dto.CoordinateSystem;
32 import org.openhab.binding.hdpowerview.internal.dto.gen3.Scene;
33 import org.openhab.binding.hdpowerview.internal.dto.gen3.SceneEvent;
34 import org.openhab.binding.hdpowerview.internal.dto.gen3.Shade;
35 import org.openhab.binding.hdpowerview.internal.dto.gen3.ShadeEvent;
36 import org.openhab.binding.hdpowerview.internal.dto.gen3.ShadePosition;
37 import org.openhab.binding.hdpowerview.internal.handler.ShadeThingHandler;
38 import org.openhab.core.library.types.DecimalType;
39 import org.openhab.core.library.types.OnOffType;
40 import org.openhab.core.library.types.PercentType;
41 import org.openhab.core.library.types.QuantityType;
42 import org.openhab.core.library.unit.Units;
43 import org.openhab.core.thing.Channel;
44 import org.openhab.core.thing.ChannelUID;
45 import org.openhab.core.thing.Thing;
46 import org.openhab.core.thing.ThingTypeUID;
47 import org.openhab.core.thing.ThingUID;
48 import org.openhab.core.thing.binding.ThingHandlerCallback;
49 import org.openhab.core.thing.binding.builder.ChannelBuilder;
50 import org.openhab.core.thing.binding.builder.ThingBuilder;
51 import org.openhab.core.types.UnDefType;
52
53 import com.google.gson.Gson;
54
55 /**
56  * Unit tests for Generation 3 DTO's.
57  *
58  * @author Andrew Fiddian-Green - Initial contribution
59  */
60 @NonNullByDefault
61 public class Generation3DtoTest {
62
63     private final Gson gson = new Gson();
64     private final ShadeCapabilitiesDatabase db = new ShadeCapabilitiesDatabase();
65
66     private String loadJson(String filename) throws IOException {
67         try (InputStream inputStream = HDPowerViewJUnitTests.class.getResourceAsStream(filename)) {
68             if (inputStream == null) {
69                 throw new IOException("inputstream is null");
70             }
71             byte[] bytes = inputStream.readAllBytes();
72             if (bytes == null) {
73                 throw new IOException("Resulting byte-array empty");
74             }
75             return new String(bytes, StandardCharsets.UTF_8);
76         }
77     }
78
79     /**
80      * Test JSON scene event response.
81      */
82     @Test
83     public void testSceneEventParsing() throws IOException {
84         String json = loadJson("gen3/scene-event.json");
85         SceneEvent sceneEvent = gson.fromJson(json, SceneEvent.class);
86         assertNotNull(sceneEvent);
87         Scene scene = sceneEvent.getScene();
88         assertNotNull(scene);
89         assertEquals("Open All Office Shades\n Open All Office Shades", scene.getName());
90         assertEquals(234, scene.getId());
91     }
92
93     /**
94      * Test JSON scenes response.
95      */
96     @Test
97     public void testScenesParsing() throws IOException {
98         String json = loadJson("gen3/scenes.json");
99         List<Scene> sceneList = List.of(gson.fromJson(json, Scene[].class));
100         assertNotNull(sceneList);
101         assertEquals(1, sceneList.size());
102         Scene scene = sceneList.get(0);
103         assertEquals("Open All Office Shades\n ABC", scene.getName());
104         assertEquals(234, scene.getId());
105     }
106
107     /**
108      * Test JSON shade event response.
109      */
110     @Test
111     public void testShadeEventParsing() throws IOException {
112         String json = loadJson("gen3/shade-event.json");
113         ShadeEvent shadeEvent = gson.fromJson(json, ShadeEvent.class);
114         assertNotNull(shadeEvent);
115         ShadePosition position = shadeEvent.getCurrentPositions();
116         assertNotNull(position);
117         assertEquals(PercentType.valueOf("99"), position.getState(CoordinateSystem.PRIMARY_POSITION));
118         assertEquals(PercentType.valueOf("98"), position.getState(CoordinateSystem.SECONDARY_POSITION));
119         assertEquals(PercentType.ZERO, position.getState(CoordinateSystem.VANE_TILT_POSITION));
120     }
121
122     /**
123      * Test JSON shade position setting.
124      */
125     @Test
126     public void testShadePositions() {
127         ShadePosition pos;
128
129         pos = new ShadePosition();
130         pos.setPosition(CoordinateSystem.PRIMARY_POSITION, new PercentType(11));
131         assertEquals(PercentType.valueOf("11"), pos.getState(CoordinateSystem.PRIMARY_POSITION));
132         assertEquals(UnDefType.UNDEF, pos.getState(CoordinateSystem.SECONDARY_POSITION));
133         assertEquals(UnDefType.UNDEF, pos.getState(CoordinateSystem.VANE_TILT_POSITION));
134
135         pos = new ShadePosition();
136         pos.setPosition(CoordinateSystem.PRIMARY_POSITION, new PercentType(11));
137         pos.setPosition(CoordinateSystem.SECONDARY_POSITION, new PercentType(22));
138         pos.setPosition(CoordinateSystem.VANE_TILT_POSITION, new PercentType(33));
139         assertEquals(PercentType.valueOf("11"), pos.getState(CoordinateSystem.PRIMARY_POSITION));
140         assertEquals(PercentType.valueOf("22"), pos.getState(CoordinateSystem.SECONDARY_POSITION));
141         assertEquals(PercentType.valueOf("33"), pos.getState(CoordinateSystem.VANE_TILT_POSITION));
142     }
143
144     /**
145      * Test JSON shades response.
146      */
147     @Test
148     public void testShadesParsing() throws IOException {
149         String json = loadJson("gen3/shades.json");
150         List<Shade> shadeList = List.of(gson.fromJson(json, Shade[].class));
151         assertNotNull(shadeList);
152         assertEquals(2, shadeList.size());
153         Shade shadeData = shadeList.get(0);
154         assertEquals("Upper Left", shadeData.getName());
155         assertEquals(2, shadeData.getId());
156         assertFalse(shadeData.isMainsPowered());
157         assertEquals(new DecimalType(66), shadeData.getBatteryLevel());
158         assertEquals(OnOffType.OFF, shadeData.getLowBattery());
159         ShadePosition positions = shadeData.getShadePositions();
160         assertNotNull(positions);
161         Integer caps = shadeData.getCapabilities();
162         assertNotNull(caps);
163         Capabilities capabilities = db.getCapabilities(caps);
164         assertTrue(capabilities.supportsPrimary());
165         assertFalse(capabilities.supportsSecondary());
166         assertFalse(capabilities.supportsTilt180());
167         assertFalse(capabilities.supportsTiltAnywhere());
168         assertFalse(capabilities.supportsTiltOnClosed());
169
170         shadeData = shadeList.get(1);
171         assertEquals(3, shadeData.getId());
172         assertTrue(shadeData.isMainsPowered());
173         positions = shadeData.getShadePositions();
174         assertNotNull(positions);
175         caps = shadeData.getCapabilities();
176         assertNotNull(caps);
177         capabilities = db.getCapabilities(caps);
178         assertTrue(capabilities.supportsPrimary());
179         assertFalse(capabilities.supportsSecondary());
180         assertFalse(capabilities.supportsTilt180());
181         assertFalse(capabilities.supportsTiltAnywhere());
182         assertTrue(capabilities.supportsTiltOnClosed());
183     }
184
185     /**
186      * Test sending properties and dynamic channel values to a shade handler.
187      */
188     @Test
189     public void testShadeHandlerPropertiesAndChannels() throws IOException {
190         ThingTypeUID thingTypeUID = new ThingTypeUID("hdpowerview:shade");
191         ThingUID thingUID = new ThingUID(thingTypeUID, "test");
192
193         List<Channel> channels = new ArrayList<Channel>();
194         for (String channelId : Set.of(CHANNEL_SHADE_POSITION, CHANNEL_SHADE_SECONDARY_POSITION, CHANNEL_SHADE_VANE,
195                 CHANNEL_SHADE_BATTERY_LEVEL, CHANNEL_SHADE_LOW_BATTERY, CHANNEL_SHADE_SIGNAL_STRENGTH)) {
196             ChannelUID channelUID = new ChannelUID(thingUID, channelId);
197             channels.add(ChannelBuilder.create(channelUID).build());
198         }
199
200         String json = loadJson("gen3/shades.json");
201         List<Shade> shadeList = List.of(gson.fromJson(json, Shade[].class));
202         assertNotNull(shadeList);
203         assertEquals(2, shadeList.size());
204
205         Thing thing = ThingBuilder.create(thingTypeUID, thingUID).withChannels(channels).build();
206         ShadeThingHandler shadeThingHandler;
207         Shade shadeData;
208
209         /*
210          * Use the first JSON Shade entry.
211          * It should support 4 dynamic channels.
212          */
213         shadeThingHandler = new ShadeThingHandler(thing);
214         shadeThingHandler.setCallback(mock(ThingHandlerCallback.class));
215         shadeData = shadeList.get(0).setId(0);
216         assertTrue(shadeData.hasFullState());
217         shadeThingHandler.notify(shadeData);
218         Thing handlerThing = shadeThingHandler.getThing();
219         assertEquals("Duette (6)", handlerThing.getProperties().get("type"));
220         assertEquals("battery", handlerThing.getProperties().get("powerType"));
221         assertEquals("3.0.359", handlerThing.getProperties().get("firmwareVersion"));
222         assertEquals(new QuantityType<>(-50, Units.DECIBEL_MILLIWATTS), shadeData.getSignalStrength());
223         assertEquals(4, handlerThing.getChannels().size());
224
225         /*
226          * Use the second JSON Shade entry.
227          * It should support only 3 dynamic channels.
228          */
229         shadeThingHandler = new ShadeThingHandler(thing);
230         shadeThingHandler.setCallback(mock(ThingHandlerCallback.class));
231         shadeData = shadeList.get(1).setId(0);
232         assertTrue(shadeData.hasFullState());
233         shadeThingHandler.notify(shadeData);
234         handlerThing = shadeThingHandler.getThing();
235         assertEquals("Silhouette (23)", handlerThing.getProperties().get("type"));
236         assertEquals("hardwired", handlerThing.getProperties().get("powerType"));
237         assertEquals("3.0.359", handlerThing.getProperties().get("firmwareVersion"));
238         assertEquals(new QuantityType<>(-51, Units.DECIBEL_MILLIWATTS), shadeData.getSignalStrength());
239         assertEquals(3, handlerThing.getChannels().size());
240     }
241
242     /**
243      * Test sending state change events to shade handler.
244      */
245     @Test
246     public void testShadeHandlerEvents() throws IOException {
247         ThingTypeUID thingTypeUID = new ThingTypeUID("hdpowerview:shade");
248         ThingUID thingUID = new ThingUID(thingTypeUID, "test");
249
250         List<Channel> channels = new ArrayList<Channel>();
251         for (String channelId : Set.of(CHANNEL_SHADE_POSITION, CHANNEL_SHADE_SECONDARY_POSITION, CHANNEL_SHADE_VANE,
252                 CHANNEL_SHADE_BATTERY_LEVEL, CHANNEL_SHADE_LOW_BATTERY, CHANNEL_SHADE_SIGNAL_STRENGTH)) {
253             ChannelUID channelUID = new ChannelUID(thingUID, channelId);
254             channels.add(ChannelBuilder.create(channelUID).build());
255         }
256
257         String json = loadJson("gen3/shades.json");
258         List<Shade> shadeList = List.of(gson.fromJson(json, Shade[].class));
259         assertNotNull(shadeList);
260         assertEquals(2, shadeList.size());
261
262         Thing thing = ThingBuilder.create(thingTypeUID, thingUID).withChannels(channels).build();
263         ShadeThingHandler shadeThingHandler;
264         Shade shadeData;
265
266         /*
267          * Use the second JSON Shade entry, which only has a primary channel.
268          */
269         shadeThingHandler = new ShadeThingHandler(thing);
270         shadeThingHandler.setCallback(mock(ThingHandlerCallback.class));
271         shadeData = shadeList.get(1).setId(0);
272         shadeThingHandler.notify(shadeData);
273
274         /*
275          * And try to update it with an event that has all 3 channels.
276          */
277         json = loadJson("gen3/shade-event.json");
278         ShadeEvent event = gson.fromJson(json, ShadeEvent.class);
279         assertNotNull(event);
280         shadeData = new Shade().setId(0).setShadePosition(event.getCurrentPositions()).setPartialState();
281         assertFalse(shadeData.hasFullState());
282         shadeThingHandler.notify(shadeData);
283     }
284 }