2 * Copyright (c) 2010-2024 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.shelly.internal.provider;
15 import static org.openhab.binding.shelly.internal.ShellyBindingConstants.*;
16 import static org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.SHELLY_API_INVTEMP;
17 import static org.openhab.binding.shelly.internal.util.ShellyUtils.*;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.LinkedHashMap;
23 import java.util.List;
25 import java.util.Optional;
27 import java.util.concurrent.CopyOnWriteArrayList;
29 import javax.measure.Unit;
31 import org.eclipse.jdt.annotation.NonNullByDefault;
32 import org.eclipse.jdt.annotation.Nullable;
33 import org.openhab.binding.shelly.internal.api.ShellyDeviceProfile;
34 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyEMNCurrentSettings;
35 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyEMNCurrentStatus;
36 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyInputState;
37 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyRollerStatus;
38 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsDimmer;
39 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsEMeter;
40 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsGlobal;
41 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsMeter;
42 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsRelay;
43 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsRgbwLight;
44 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellySettingsStatus;
45 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyShortLightStatus;
46 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusLightChannel;
47 import org.openhab.binding.shelly.internal.api1.Shelly1ApiJsonDTO.ShellyStatusSensor;
48 import org.openhab.binding.shelly.internal.handler.ShellyThingInterface;
49 import org.openhab.core.thing.Channel;
50 import org.openhab.core.thing.ChannelUID;
51 import org.openhab.core.thing.Thing;
52 import org.openhab.core.thing.binding.builder.ChannelBuilder;
53 import org.openhab.core.thing.type.ChannelKind;
54 import org.openhab.core.thing.type.ChannelTypeUID;
55 import org.openhab.core.types.StateOption;
56 import org.osgi.service.component.annotations.Activate;
57 import org.osgi.service.component.annotations.Component;
58 import org.osgi.service.component.annotations.Reference;
61 * The {@link #CHANNEL_DEFINITIONS} defines channel information for dynamically created channels. Those will be
62 * added on the first thing status update
64 * @author Markus Michels - Initial contribution
67 @Component(service = ShellyChannelDefinitions.class)
68 public class ShellyChannelDefinitions {
70 public static final String ITEMT_STRING = "String";
71 public static final String ITEMT_NUMBER = "Number";
72 public static final String ITEMT_SWITCH = "Switch";
73 public static final String ITEMT_CONTACT = "Contact";
74 public static final String ITEMT_ROLLER = "Rollershutter";
75 public static final String ITEMT_DIMMER = "Dimmer";
76 public static final String ITEMT_LOCATION = "Location";
77 public static final String ITEMT_DATETIME = "DateTime";
78 public static final String ITEMT_TEMP = "Number:Temperature";
79 public static final String ITEMT_LUX = "Number:Illuminance";
80 public static final String ITEMT_POWER = "Number:Power";
81 public static final String ITEMT_ENERGY = "Number:Energy";
82 public static final String ITEMT_VOLT = "Number:ElectricPotential";
83 public static final String ITEMT_AMP = "Number:ElectricCurrent";
84 public static final String ITEMT_ANGLE = "Number:Angle";
85 public static final String ITEMT_DISTANCE = "Number:Length";
86 public static final String ITEMT_SPEED = "Number:Speed";
87 public static final String ITEMT_VOLUME = "Number:Volume";
88 public static final String ITEMT_TIME = "Number:Time";
89 public static final String ITEMT_PERCENT = "Number:Dimensionless";
91 // shortcuts to avoid line breaks (make code more readable)
92 private static final String CHGR_DEVST = CHANNEL_GROUP_DEV_STATUS;
93 private static final String CHGR_RELAY = CHANNEL_GROUP_RELAY_CONTROL;
94 private static final String CHGR_ROLLER = CHANNEL_GROUP_ROL_CONTROL;
95 private static final String CHGR_LIGHT = CHANNEL_GROUP_LIGHT_CONTROL;
96 private static final String CHGR_LIGHTCH = CHANNEL_GROUP_LIGHT_CHANNEL;
97 private static final String CHGR_STATUS = CHANNEL_GROUP_STATUS;
98 private static final String CHGR_METER = CHANNEL_GROUP_METER;
99 private static final String CHGR_EMN = CHANNEL_GROUP_NMETER;
100 private static final String CHGR_SENSOR = CHANNEL_GROUP_SENSOR;
101 private static final String CHGR_CONTROL = CHANNEL_GROUP_CONTROL;
102 private static final String CHGR_BAT = CHANNEL_GROUP_BATTERY;
104 public static final String PREFIX_GROUP = "group-type." + BINDING_ID + ".";
105 public static final String PREFIX_CHANNEL = "channel-type." + BINDING_ID + ".";
107 public class OptionEntry {
108 public ChannelTypeUID uid;
112 public OptionEntry(ChannelTypeUID uid, String key, String value) {
119 private final CopyOnWriteArrayList<OptionEntry> stateOptions = new CopyOnWriteArrayList<>();
121 private static final ChannelMap CHANNEL_DEFINITIONS = new ChannelMap();
124 public ShellyChannelDefinitions(@Reference ShellyTranslationProvider translationProvider) {
125 ShellyTranslationProvider m = translationProvider;
130 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_NAME, "deviceName", ITEMT_STRING))
131 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_GATEWAY, "gatewayDevice", ITEMT_STRING))
132 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ITEMP, "system:indoor-temperature", ITEMT_TEMP))
133 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_WAKEUP, "sensorWakeup", ITEMT_STRING))
134 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCUWATTS, "meterAccuWatts", ITEMT_POWER))
135 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCUTOTAL, "meterAccuTotal", ITEMT_ENERGY))
136 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_ACCURETURNED, "meterAccuReturned", ITEMT_ENERGY))
137 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_RESETTOTAL, "meterResetTotals", ITEMT_SWITCH))
138 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_VOLTAGE, "supplyVoltage", ITEMT_VOLT))
139 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_CHARGER, "charger", ITEMT_SWITCH))
140 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_LED_STATUS_DISABLE, "ledStatusDisable", ITEMT_SWITCH))
141 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_LED_POWER_DISABLE, "ledPowerDisable", ITEMT_SWITCH))
142 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_SELFTTEST, "selfTest", ITEMT_STRING))
143 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_UPTIME, "uptime", ITEMT_NUMBER))
144 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_HEARTBEAT, "heartBeat", ITEMT_DATETIME))
145 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_UPDATE, "updateAvailable", ITEMT_SWITCH))
146 .add(new ShellyChannel(m, CHGR_DEVST, CHANNEL_DEVST_CALIBRATED, "calibrated", ITEMT_SWITCH))
149 .add(new ShellyChannel(m, CHGR_RELAY, CHANNEL_OUTPUT_NAME, "outputName", ITEMT_STRING))
150 .add(new ShellyChannel(m, CHGR_RELAY, CHANNEL_OUTPUT, "system:power", ITEMT_SWITCH))
151 .add(new ShellyChannel(m, CHGR_RELAY, CHANNEL_INPUT, "inputState", ITEMT_SWITCH))
152 .add(new ShellyChannel(m, CHGR_RELAY, CHANNEL_BUTTON_TRIGGER, "system:button", ITEMT_STRING))
153 .add(new ShellyChannel(m, CHGR_RELAY, CHANNEL_STATUS_EVENTTYPE, "lastEvent", ITEMT_STRING))
154 .add(new ShellyChannel(m, CHGR_RELAY, CHANNEL_STATUS_EVENTCOUNT, "eventCount", ITEMT_NUMBER))
155 .add(new ShellyChannel(m, CHGR_RELAY, CHANNEL_TIMER_AUTOON, "timerAutoOn", ITEMT_TIME))
156 .add(new ShellyChannel(m, CHGR_RELAY, CHANNEL_TIMER_AUTOOFF, "timerAutoOff", ITEMT_TIME))
157 .add(new ShellyChannel(m, CHGR_RELAY, CHANNEL_TIMER_ACTIVE, "timerActive", ITEMT_SWITCH))
160 .add(new ShellyChannel(m, CHANNEL_GROUP_DIMMER_CONTROL, CHANNEL_BRIGHTNESS, "dimmerBrightness",
164 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_ROL_CONTROL_CONTROL, "rollerShutter", ITEMT_ROLLER))
165 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_ROL_CONTROL_POS, "rollerPosition", ITEMT_DIMMER))
166 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_ROL_CONTROL_FAV, "rollerFavorite", ITEMT_NUMBER))
167 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_ROL_CONTROL_STATE, "rollerState", ITEMT_STRING))
168 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_ROL_CONTROL_STOPR, "rollerStop", ITEMT_STRING))
169 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_ROL_CONTROL_SAFETY, "rollerSafety", ITEMT_SWITCH))
170 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_INPUT, "inputState", ITEMT_SWITCH))
171 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_STATUS_EVENTTYPE, "lastEvent", ITEMT_STRING))
172 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_STATUS_EVENTCOUNT, "eventCount", ITEMT_NUMBER))
173 .add(new ShellyChannel(m, CHGR_ROLLER, CHANNEL_EVENT_TRIGGER, "system:button", "system:button"))
176 .add(new ShellyChannel(m, CHGR_LIGHT, CHANNEL_INPUT, "inputState", ITEMT_SWITCH))
177 .add(new ShellyChannel(m, CHGR_LIGHT, CHANNEL_BUTTON_TRIGGER, "system:button", ITEMT_STRING))
178 .add(new ShellyChannel(m, CHGR_LIGHT, CHANNEL_STATUS_EVENTTYPE, "lastEvent", ITEMT_STRING))
179 .add(new ShellyChannel(m, CHGR_LIGHT, CHANNEL_STATUS_EVENTCOUNT, "eventCount", ITEMT_NUMBER))
180 .add(new ShellyChannel(m, CHANNEL_GROUP_WHITE_CONTROL, CHANNEL_BRIGHTNESS, "whiteBrightness",
182 .add(new ShellyChannel(m, CHANNEL_GROUP_WHITE_CONTROL, CHANNEL_COLOR_TEMP, "whiteTemp", ITEMT_DIMMER))
185 .add(new ShellyChannel(m, CHGR_LIGHT, CHANNEL_LIGHT_POWER, "system:power", ITEMT_SWITCH))
186 .add(new ShellyChannel(m, CHGR_LIGHT, CHANNEL_TIMER_AUTOON, "timerAutoOn", ITEMT_TIME))
187 .add(new ShellyChannel(m, CHGR_LIGHT, CHANNEL_TIMER_AUTOOFF, "timerAutoOff", ITEMT_TIME))
188 .add(new ShellyChannel(m, CHGR_LIGHT, CHANNEL_TIMER_ACTIVE, "timerActive", ITEMT_SWITCH))
190 .add(new ShellyChannel(m, CHGR_LIGHTCH, CHANNEL_BRIGHTNESS, "whiteBrightness", ITEMT_DIMMER))
191 .add(new ShellyChannel(m, CHGR_LIGHTCH, CHANNEL_TIMER_AUTOON, "timerAutoOn", ITEMT_TIME))
192 .add(new ShellyChannel(m, CHGR_LIGHTCH, CHANNEL_TIMER_AUTOOFF, "timerAutoOff", ITEMT_TIME))
193 .add(new ShellyChannel(m, CHGR_LIGHTCH, CHANNEL_TIMER_ACTIVE, "timerActive", ITEMT_SWITCH))
196 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_METER_CURRENTWATTS, "meterWatts", ITEMT_POWER))
197 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_METER_TOTALKWH, "meterTotal", ITEMT_ENERGY))
198 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_METER_LASTMIN1, "lastPower1", ITEMT_POWER))
199 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_LAST_UPDATE, "lastUpdate", ITEMT_DATETIME))
202 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_TOTALRET, "meterReturned", ITEMT_ENERGY))
203 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_REACTWATTS, "meterReactive", ITEMT_POWER))
204 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_VOLTAGE, "meterVoltage", ITEMT_VOLT))
205 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_CURRENT, "meterCurrent", ITEMT_AMP))
206 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_PFACTOR, "meterPowerFactor", ITEMT_NUMBER))
207 .add(new ShellyChannel(m, CHGR_METER, CHANNEL_EMETER_RESETTOTAL, "meterResetTotals", ITEMT_SWITCH))
209 // 3EM: neutral current (emeter_n)
210 .add(new ShellyChannel(m, CHGR_EMN, CHANNEL_NMETER_CURRENT, "ncurrent", ITEMT_AMP))
211 .add(new ShellyChannel(m, CHGR_EMN, CHANNEL_NMETER_IXSUM, "ixsum", ITEMT_AMP))
212 .add(new ShellyChannel(m, CHGR_EMN, CHANNEL_NMETER_MTRESHHOLD, "nmTreshhold", ITEMT_AMP))
213 .add(new ShellyChannel(m, CHGR_EMN, CHANNEL_NMETER_MISMATCH, "nmismatch", ITEMT_SWITCH))
216 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TEMP, "system:indoor-temperature", ITEMT_TEMP))
217 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_HUM, "system:atmospheric-humidity",
219 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_LUX, "sensorLux", ITEMT_LUX))
220 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_ILLUM, "sensorIllumination", ITEMT_STRING))
221 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VOLTAGE, "sensorADC", ITEMT_VOLT))
222 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_STATE, "sensorContact", ITEMT_CONTACT))
223 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_SSTATE, "sensorState", ITEMT_STRING))
224 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TILT, "sensorTilt", ITEMT_ANGLE))
225 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION, "sensorMotion", ITEMT_SWITCH))
226 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION_TS, "motionTimestamp", ITEMT_DATETIME))
227 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION_ACT, "motionActive", ITEMT_SWITCH))
228 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VIBRATION, "sensorVibration", ITEMT_SWITCH))
229 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_FLOOD, "sensorFlood", ITEMT_SWITCH))
230 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_SMOKE, "sensorSmoke", ITEMT_SWITCH))
231 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MUTE, "sensorMute", ITEMT_SWITCH))
232 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_PPM, "sensorPPM", ITEMT_NUMBER))
233 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VALVE, "sensorValve", ITEMT_STRING))
234 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_ALARM_STATE, "alarmState", ITEMT_STRING))
235 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_ERROR, "sensorError", ITEMT_STRING))
236 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_LAST_UPDATE, "lastUpdate", ITEMT_DATETIME))
237 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_SLEEPTIME, "sensorSleepTime", ITEMT_NUMBER))
238 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSE_KEY, "senseKey", ITEMT_STRING)) // Sense
241 .add(new ShellyChannel(m, CHGR_STATUS, CHANNEL_INPUT, "inputState", ITEMT_SWITCH))
242 .add(new ShellyChannel(m, CHGR_STATUS, CHANNEL_STATUS_EVENTTYPE, "lastEvent", ITEMT_STRING))
243 .add(new ShellyChannel(m, CHGR_STATUS, CHANNEL_STATUS_EVENTCOUNT, "eventCount", ITEMT_NUMBER))
244 .add(new ShellyChannel(m, CHGR_STATUS, CHANNEL_BUTTON_TRIGGER, "system:button", ITEMT_STRING))
245 .add(new ShellyChannel(m, CHGR_STATUS, CHANNEL_LAST_UPDATE, "lastUpdate", ITEMT_DATETIME))
247 // Addon with external sensors
248 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP1, "system:outdoor-temperature", ITEMT_TEMP))
249 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP2, "system:outdoor-temperature", ITEMT_TEMP))
250 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP3, "system:outdoor-temperature", ITEMT_TEMP))
251 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP4, "system:outdoor-temperature", ITEMT_TEMP))
252 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP5, "system:outdoor-temperature", ITEMT_TEMP))
253 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_HUMIDITY, "system:atmospheric-humidity",
255 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_VOLTAGE, "sensorExtVolt", ITEMT_VOLT))
256 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_INPUT1, "sensorContact", ITEMT_CONTACT))
257 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_DIGITALINPUT, "sensorExtDigitalInput",
259 .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_ESENSOR_ANALOGINPUT, "sensorExtAnalogInput",
263 .add(new ShellyChannel(m, CHGR_BAT, CHANNEL_SENSOR_BAT_LEVEL, "system:battery-level", ITEMT_PERCENT))
264 .add(new ShellyChannel(m, CHGR_BAT, CHANNEL_SENSOR_BAT_LOW, "system:low-battery", ITEMT_SWITCH))
267 .add(new ShellyChannel(m, CHGR_CONTROL, CHANNEL_CONTROL_POSITION, "sensorPosition", ITEMT_DIMMER))
268 .add(new ShellyChannel(m, CHGR_CONTROL, CHANNEL_CONTROL_MODE, "controlMode", ITEMT_STRING))
269 .add(new ShellyChannel(m, CHGR_CONTROL, CHANNEL_CONTROL_PROFILE, "controlProfile", ITEMT_STRING))
270 .add(new ShellyChannel(m, CHGR_CONTROL, CHANNEL_CONTROL_SETTEMP, "targetTemp", ITEMT_TEMP))
271 .add(new ShellyChannel(m, CHGR_CONTROL, CHANNEL_CONTROL_BCONTROL, "boostControl", ITEMT_SWITCH))
272 .add(new ShellyChannel(m, CHGR_CONTROL, CHANNEL_CONTROL_BTIMER, "boostTimer", ITEMT_TIME))
273 .add(new ShellyChannel(m, CHGR_CONTROL, CHANNEL_CONTROL_SCHEDULE, "controlSchedule", ITEMT_SWITCH));
276 public static @Nullable ShellyChannel getDefinition(String channelName) throws IllegalArgumentException {
277 String group = substringBefore(channelName, "#");
278 String channel = substringAfter(channelName, "#");
280 if (group.startsWith(CHANNEL_GROUP_METER)) {
281 group = CHANNEL_GROUP_METER; // map meter1..n to meter
282 } else if (group.startsWith(CHANNEL_GROUP_RELAY_CONTROL)) {
283 group = CHANNEL_GROUP_RELAY_CONTROL; // map meter1..n to meter
284 } else if (group.startsWith(CHANNEL_GROUP_LIGHT_CHANNEL)) {
285 group = CHANNEL_GROUP_LIGHT_CHANNEL;
286 } else if (group.startsWith(CHANNEL_GROUP_STATUS)) {
287 group = CHANNEL_GROUP_STATUS; // map status1..n to meter
290 if (channel.startsWith(CHANNEL_INPUT)) {
291 channel = CHANNEL_INPUT;
292 } else if (channel.startsWith(CHANNEL_BUTTON_TRIGGER)) {
293 channel = CHANNEL_BUTTON_TRIGGER;
294 } else if (channel.startsWith(CHANNEL_STATUS_EVENTTYPE)) {
295 channel = CHANNEL_STATUS_EVENTTYPE;
296 } else if (channel.startsWith(CHANNEL_STATUS_EVENTCOUNT)) {
297 channel = CHANNEL_STATUS_EVENTCOUNT;
300 String channelId = group + "#" + channel;
301 return CHANNEL_DEFINITIONS.get(channelId);
305 * Auto-create relay channels depending on relay type/mode
307 * @return {@code ArrayList<Channel>} of channels to be added to the thing
309 public static Map<String, Channel> createDeviceChannels(final Thing thing, final ShellyDeviceProfile profile,
310 final ShellySettingsStatus status) {
311 Map<String, Channel> add = new LinkedHashMap<>();
313 addChannel(thing, add, profile.settings.name != null, CHGR_DEVST, CHANNEL_DEVST_NAME);
314 addChannel(thing, add, !profile.gateway.isEmpty() || profile.isBlu, CHGR_DEVST, CHANNEL_DEVST_GATEWAY);
316 if (!profile.isSensor && !profile.isIX
317 && ((status.temperature != null && getDouble(status.temperature) != SHELLY_API_INVTEMP)
318 || (status.tmp != null && getDouble(status.tmp.tC) != SHELLY_API_INVTEMP))) {
319 // Only some devices report the internal device temp
320 boolean hasTemp = !profile.isLight
321 && (status.temperature != null || (status.tmp != null && !profile.isSensor));
322 if (hasTemp && profile.isGen2 && (profile.numMeters > 0 && !profile.hasRelays)) // Shely Plus PM Mini
326 addChannel(thing, add, hasTemp, CHGR_DEVST, CHANNEL_DEVST_ITEMP);
328 addChannel(thing, add, profile.settings.sleepTime != null, CHGR_SENSOR, CHANNEL_SENSOR_SLEEPTIME);
330 // If device has more than 1 meter the channel accumulatedWatts receives the accumulated value
331 boolean accuChannel = profile.hasRelays && profile.numMeters > 1 && !profile.isRoller && !profile.isRGBW2;
332 addChannel(thing, add, accuChannel, CHGR_DEVST, CHANNEL_DEVST_ACCUWATTS);
333 addChannel(thing, add, accuChannel, CHGR_DEVST, CHANNEL_DEVST_ACCUTOTAL);
334 addChannel(thing, add, accuChannel && (status.emeters != null), CHGR_DEVST, CHANNEL_DEVST_ACCURETURNED);
335 addChannel(thing, add, profile.is3EM, CHGR_DEVST, CHANNEL_DEVST_RESETTOTAL); // 3EM
336 addChannel(thing, add, status.voltage != null || profile.settings.supplyVoltage != null, CHGR_DEVST,
337 CHANNEL_DEVST_VOLTAGE);
338 addChannel(thing, add,
339 profile.status.uptime != null && (!profile.hasBattery || profile.isMotion || profile.isTRV), CHGR_DEVST,
340 CHANNEL_DEVST_UPTIME);
341 addChannel(thing, add, true, CHGR_DEVST, CHANNEL_DEVST_UPDATE);
342 addChannel(thing, add, true, CHGR_DEVST, CHANNEL_DEVST_HEARTBEAT);
343 addChannel(thing, add, profile.settings.ledPowerDisable != null, CHGR_DEVST, CHANNEL_LED_POWER_DISABLE);
344 addChannel(thing, add, profile.settings.ledStatusDisable != null, CHGR_DEVST, CHANNEL_LED_STATUS_DISABLE); // WiFi
345 addChannel(thing, add, profile.settings.calibrated != null, CHGR_DEVST, CHANNEL_DEVST_CALIBRATED);
351 * Auto-create relay channels depending on relay type/mode
353 * @return {@code ArrayList<Channel>} of channels to be added to the thing
355 public static Map<String, Channel> createRelayChannels(final Thing thing, final ShellyDeviceProfile profile,
356 final ShellySettingsRelay rstatus, int idx) {
357 Map<String, Channel> add = new LinkedHashMap<>();
358 String group = profile.getControlGroup(idx);
360 if (profile.settings.relays != null) {
361 ShellySettingsRelay rs = profile.settings.relays.get(idx);
362 addChannel(thing, add, rs.ison != null, group, CHANNEL_OUTPUT);
363 addChannel(thing, add, rs.name != null, group, CHANNEL_OUTPUT_NAME);
365 boolean timer = rs.hasTimer != null || rstatus.hasTimer != null; // Dimmer 1/2 have
366 addChannel(thing, add, timer, group, CHANNEL_TIMER_ACTIVE);
367 addChannel(thing, add, rs.autoOn != null, group, CHANNEL_TIMER_AUTOON);
368 addChannel(thing, add, rs.autoOff != null, group, CHANNEL_TIMER_AUTOOFF);
371 // Shelly 1/1PM and Plus 1/1PM Addon
372 boolean addon = profile.settings.extSwitch != null && profile.settings.extSwitch.input0 != null
373 && idx == getInteger(profile.settings.extSwitch.input0.relayNum);
375 addChannel(thing, add, addon, CHGR_SENSOR,
376 CHANNEL_ESENSOR_INPUT + (profile.settings.extSwitch.input0.relayNum + 1));
378 if (profile.status.extTemperature != null) {
379 addChannel(thing, add, profile.status.extTemperature.sensor1 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP1);
380 addChannel(thing, add, profile.status.extTemperature.sensor2 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP2);
381 addChannel(thing, add, profile.status.extTemperature.sensor3 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP3);
382 addChannel(thing, add, profile.status.extTemperature.sensor4 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP4);
383 addChannel(thing, add, profile.status.extTemperature.sensor5 != null, CHGR_SENSOR, CHANNEL_ESENSOR_TEMP5);
385 addChannel(thing, add, profile.status.extHumidity != null && profile.status.extHumidity.sensor1 != null,
386 CHGR_SENSOR, CHANNEL_ESENSOR_HUMIDITY);
387 addChannel(thing, add, profile.status.extVoltage != null, CHGR_SENSOR, CHANNEL_ESENSOR_VOLTAGE);
388 addChannel(thing, add, profile.status.extDigitalInput != null, CHGR_SENSOR, CHANNEL_ESENSOR_DIGITALINPUT);
389 addChannel(thing, add, profile.status.extAnalogInput != null, CHGR_SENSOR, CHANNEL_ESENSOR_ANALOGINPUT);
394 public static Map<String, Channel> createDimmerChannels(final Thing thing, final ShellyDeviceProfile profile,
395 final ShellySettingsStatus dstatus, int idx) {
396 Map<String, Channel> add = new LinkedHashMap<>();
397 String group = profile.getControlGroup(idx);
399 // Shelly Dimmer has an additional brightness channel
400 addChannel(thing, add, profile.isDimmer, group, CHANNEL_BRIGHTNESS);
402 if (profile.settings.dimmers != null) {
403 ShellySettingsDimmer ds = profile.settings.dimmers.get(idx);
404 addChannel(thing, add, ds.name != null, group, CHANNEL_OUTPUT_NAME);
405 addChannel(thing, add, ds.autoOn != null, group, CHANNEL_TIMER_AUTOON);
406 addChannel(thing, add, ds.autoOff != null, group, CHANNEL_TIMER_AUTOOFF);
407 ShellyShortLightStatus dss = dstatus.dimmers.get(idx);
408 addChannel(thing, add, dss != null && dss.hasTimer != null, group, CHANNEL_TIMER_ACTIVE);
413 public static Map<String, Channel> createLightChannels(final Thing thing, final ShellyDeviceProfile profile,
414 final ShellyStatusLightChannel status, int idx) {
415 Map<String, Channel> add = new LinkedHashMap<>();
416 String group = profile.getControlGroup(idx);
418 if (profile.settings.lights != null) {
419 ShellySettingsRgbwLight light = profile.settings.lights.get(idx);
420 String whiteGroup = profile.isRGBW2 ? group : CHANNEL_GROUP_WHITE_CONTROL;
421 // Create power channel in color mode and brightness channel in white mode
422 addChannel(thing, add, profile.inColor, group, CHANNEL_LIGHT_POWER);
423 addChannel(thing, add, light.autoOn != null, group, CHANNEL_TIMER_AUTOON);
424 addChannel(thing, add, light.autoOff != null, group, CHANNEL_TIMER_AUTOOFF);
425 addChannel(thing, add, status.hasTimer != null, group, CHANNEL_TIMER_ACTIVE);
426 addChannel(thing, add, light.brightness != null, whiteGroup, CHANNEL_BRIGHTNESS);
427 addChannel(thing, add, light.temp != null, whiteGroup, CHANNEL_COLOR_TEMP);
433 public static Map<String, Channel> createInputChannels(final Thing thing, final ShellyDeviceProfile profile,
434 final ShellySettingsStatus status) {
435 Map<String, Channel> add = new LinkedHashMap<>();
436 if (status.inputs != null) {
437 // Create channels per input. For devices with more than 1 input (Dimmer, 1L) multiple channel sets are
438 // created by adding the index to the channel name
439 for (int i = 0; i < profile.numInputs; i++) {
440 String group = profile.getInputGroup(i);
441 String suffix = profile.getInputSuffix(i); // multi ? String.valueOf(i + 1) : "";
442 addChannel(thing, add, !profile.isButton, group, CHANNEL_INPUT + suffix);
443 addChannel(thing, add, true, group,
444 (!profile.isRoller ? CHANNEL_BUTTON_TRIGGER + suffix : CHANNEL_EVENT_TRIGGER));
445 if (profile.inButtonMode(i)) {
446 ShellyInputState input = status.inputs.get(i);
447 addChannel(thing, add, input.event != null, group, CHANNEL_STATUS_EVENTTYPE + suffix);
448 addChannel(thing, add, input.eventCount != null, group, CHANNEL_STATUS_EVENTCOUNT + suffix);
451 } else if (status.input != null) {
452 // old RGBW2 firmware
453 String group = profile.getInputGroup(0);
454 addChannel(thing, add, true, group, CHANNEL_INPUT);
455 addChannel(thing, add, true, group, CHANNEL_BUTTON_TRIGGER);
460 public static Map<String, Channel> createRollerChannels(Thing thing, final ShellyRollerStatus roller) {
461 Map<String, Channel> add = new LinkedHashMap<>();
462 addChannel(thing, add, true, CHGR_ROLLER, CHANNEL_ROL_CONTROL_CONTROL);
463 addChannel(thing, add, true, CHGR_ROLLER, CHANNEL_ROL_CONTROL_STATE);
464 addChannel(thing, add, true, CHGR_ROLLER, CHANNEL_EVENT_TRIGGER);
465 addChannel(thing, add, roller.currentPos != null, CHGR_ROLLER, CHANNEL_ROL_CONTROL_POS);
466 addChannel(thing, add, roller.stopReason != null, CHGR_ROLLER, CHANNEL_ROL_CONTROL_STOPR);
467 addChannel(thing, add, roller.safetySwitch != null, CHGR_ROLLER, CHANNEL_ROL_CONTROL_SAFETY);
469 ShellyThingInterface handler = (ShellyThingInterface) thing.getHandler();
470 if (handler != null) {
471 ShellySettingsGlobal settings = handler.getProfile().settings;
472 if (getBool(settings.favoritesEnabled) && settings.favorites != null) {
473 addChannel(thing, add, roller.currentPos != null, CHGR_ROLLER, CHANNEL_ROL_CONTROL_FAV);
479 public static Map<String, Channel> createMeterChannels(Thing thing, final ShellySettingsMeter meter, String group) {
480 Map<String, Channel> newChannels = new LinkedHashMap<>();
481 addChannel(thing, newChannels, meter.power != null, group, CHANNEL_METER_CURRENTWATTS);
482 addChannel(thing, newChannels, meter.total != null, group, CHANNEL_METER_TOTALKWH);
483 addChannel(thing, newChannels, meter.counters != null && meter.counters[0] != null, group,
484 CHANNEL_METER_LASTMIN1);
485 addChannel(thing, newChannels, meter.timestamp != null, group, CHANNEL_LAST_UPDATE);
489 public static Map<String, Channel> createEMeterChannels(final Thing thing, final ShellyDeviceProfile profile,
490 final ShellySettingsEMeter emeter, String group) {
491 Map<String, Channel> newChannels = new LinkedHashMap<>();
492 addChannel(thing, newChannels, emeter.power != null, group, CHANNEL_METER_CURRENTWATTS);
493 addChannel(thing, newChannels, emeter.total != null, group, CHANNEL_METER_TOTALKWH);
494 addChannel(thing, newChannels, emeter.totalReturned != null, group, CHANNEL_EMETER_TOTALRET);
495 addChannel(thing, newChannels, emeter.reactive != null, group, CHANNEL_EMETER_REACTWATTS);
496 addChannel(thing, newChannels, emeter.voltage != null, group, CHANNEL_EMETER_VOLTAGE);
497 addChannel(thing, newChannels, emeter.current != null, group, CHANNEL_EMETER_CURRENT);
498 addChannel(thing, newChannels, emeter.pf != null, group, CHANNEL_EMETER_PFACTOR); // EM has no PF. but power
499 addChannel(thing, newChannels, true, group, CHANNEL_LAST_UPDATE);
500 ShellyThingInterface handler = (ShellyThingInterface) thing.getHandler();
501 if (handler != null) {
502 addChannel(thing, newChannels, handler.getProfile().isEM50, group, CHANNEL_DEVST_RESETTOTAL); // 3EM
507 public static Map<String, Channel> createEMNCurrentChannels(final Thing thing, ShellyEMNCurrentSettings settings,
508 ShellyEMNCurrentStatus status) {
509 String group = CHANNEL_GROUP_NMETER;
510 Map<String, Channel> newChannels = new LinkedHashMap<>();
511 addChannel(thing, newChannels, status.current != null, group, CHANNEL_NMETER_CURRENT);
512 addChannel(thing, newChannels, status.ixsum != null, group, CHANNEL_NMETER_IXSUM);
513 addChannel(thing, newChannels, status.mismatch != null, group, CHANNEL_NMETER_MISMATCH);
514 addChannel(thing, newChannels, settings.mismatchThreshold != null, group, CHANNEL_NMETER_MTRESHHOLD);
518 public static Map<String, Channel> createSensorChannels(final Thing thing, final ShellyDeviceProfile profile,
519 final ShellyStatusSensor sdata) {
520 Map<String, Channel> newChannels = new LinkedHashMap<>();
523 addChannel(thing, newChannels, sdata.tmp != null || sdata.thermostats != null, CHANNEL_GROUP_SENSOR,
524 CHANNEL_SENSOR_TEMP);
525 addChannel(thing, newChannels, sdata.hum != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_HUM);
526 addChannel(thing, newChannels, sdata.lux != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_LUX);
527 addChannel(thing, newChannels, sdata.lux != null && sdata.lux.illumination != null, CHANNEL_GROUP_SENSOR,
528 CHANNEL_SENSOR_ILLUM);
529 addChannel(thing, newChannels, sdata.flood != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_FLOOD);
530 addChannel(thing, newChannels, sdata.smoke != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_SMOKE);
531 addChannel(thing, newChannels, sdata.mute != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_MUTE);
532 addChannel(thing, newChannels, profile.settings.externalPower != null || sdata.charger != null, CHGR_DEVST,
533 CHANNEL_DEVST_CHARGER);
534 addChannel(thing, newChannels, sdata.motion != null || (sdata.sensor != null && sdata.sensor.motion != null),
535 CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_MOTION);
536 if (sdata.sensor != null) { // DW, Sense or Motion
537 addChannel(thing, newChannels, sdata.sensor.state != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_STATE); // DW/DW2
538 addChannel(thing, newChannels, sdata.sensor.motionActive != null, CHANNEL_GROUP_SENSOR, // Motion
539 CHANNEL_SENSOR_MOTION_ACT);
540 addChannel(thing, newChannels, sdata.sensor.motionTimestamp != null, CHANNEL_GROUP_SENSOR, // Motion
541 CHANNEL_SENSOR_MOTION_TS);
542 addChannel(thing, newChannels, sdata.sensor.vibration != null, CHANNEL_GROUP_SENSOR,
543 CHANNEL_SENSOR_VIBRATION);
545 // Create tilt for DW/DW2, for BLU DW create channel even tilt is currently not reported
546 if (sdata.accel != null || (profile.isBlu && profile.isDW && sdata.lux != null)) {
547 addChannel(thing, newChannels, sdata.accel.tilt != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TILT);
551 if (sdata.gasSensor != null) {
552 addChannel(thing, newChannels, sdata.gasSensor.selfTestState != null, CHGR_DEVST, CHANNEL_DEVST_SELFTTEST);
553 addChannel(thing, newChannels, sdata.gasSensor.sensorState != null, CHANNEL_GROUP_SENSOR,
554 CHANNEL_SENSOR_SSTATE);
555 addChannel(thing, newChannels, sdata.concentration != null && sdata.concentration.ppm != null,
556 CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_PPM);
557 addChannel(thing, newChannels, sdata.valves != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VALVE);
558 addChannel(thing, newChannels, sdata.gasSensor.sensorState != null, CHANNEL_GROUP_SENSOR,
559 CHANNEL_SENSOR_ALARM_STATE);
563 addChannel(thing, newChannels, profile.isSense, CHANNEL_GROUP_SENSOR, CHANNEL_SENSE_KEY);
566 addChannel(thing, newChannels, sdata.adcs != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VOLTAGE);
570 addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SETTEMP);
571 addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_BCONTROL);
572 addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_BTIMER);
573 addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_POSITION);
574 addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_MODE);
575 addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_PROFILE);
576 addChannel(thing, newChannels, true, CHANNEL_GROUP_CONTROL, CHANNEL_CONTROL_SCHEDULE);
577 addChannel(thing, newChannels, true, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_STATE);
581 if (sdata.bat != null) {
582 addChannel(thing, newChannels, sdata.bat.value != null, CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LEVEL);
583 addChannel(thing, newChannels, sdata.bat.value != null, CHANNEL_GROUP_BATTERY, CHANNEL_SENSOR_BAT_LOW);
586 addChannel(thing, newChannels, sdata.sensorError != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ERROR);
587 addChannel(thing, newChannels, sdata.actReasons != null, CHGR_DEVST, CHANNEL_DEVST_WAKEUP);
588 addChannel(thing, newChannels, true, profile.isButton ? CHANNEL_GROUP_STATUS : CHANNEL_GROUP_SENSOR,
589 CHANNEL_LAST_UPDATE);
593 public ChannelTypeUID getChannelTypeUID(String channelId) {
594 ShellyChannel channelDef = getDefinition(channelId);
595 if (channelDef != null) {
596 return new ChannelTypeUID(BINDING_ID, channelDef.typeId);
598 throw new IllegalArgumentException("Invalid channelId:" + channelId);
601 private static void addChannel(Thing thing, Map<String, Channel> newChannels, boolean supported, String group,
602 String channelName) throws IllegalArgumentException {
604 String channelId = group + "#" + channelName;
605 ChannelUID channelUID = new ChannelUID(thing.getUID(), channelId);
606 ShellyChannel channelDef = getDefinition(channelId);
607 if (channelDef != null) {
608 ChannelTypeUID channelTypeUID = channelDef.typeId.contains("system:")
609 ? new ChannelTypeUID(channelDef.typeId)
610 : new ChannelTypeUID(BINDING_ID, channelDef.typeId);
611 ChannelBuilder builder;
612 if ("system:button".equalsIgnoreCase(channelDef.typeId)) {
613 builder = ChannelBuilder.create(channelUID, null).withKind(ChannelKind.TRIGGER);
615 builder = ChannelBuilder.create(channelUID, channelDef.itemType);
617 if (!channelDef.label.isEmpty()) {
618 char grseq = lastChar(group);
619 char chseq = lastChar(channelName);
620 char sequence = isDigit(chseq) ? chseq : grseq;
621 String label = !isDigit(sequence) ? channelDef.label : channelDef.label + " " + sequence;
622 builder.withLabel(label);
624 if (!channelDef.description.isEmpty()) {
625 builder.withDescription(channelDef.description);
627 newChannels.put(channelId, builder.withType(channelTypeUID).build());
632 public List<StateOption> getStateOptions(ChannelTypeUID uid) {
633 List<StateOption> options = new ArrayList<>();
634 for (OptionEntry oe : stateOptions) {
635 if (oe.uid.equals(uid)) {
636 options.add(new StateOption(oe.key, oe.value));
642 public void addStateOption(String channelId, String key, String value) {
643 ChannelTypeUID uid = getChannelTypeUID(channelId);
644 stateOptions.addIfAbsent(new OptionEntry(uid, key, value));
647 public void clearStateOptions(String channelId) {
648 ChannelTypeUID uid = getChannelTypeUID(channelId);
649 for (OptionEntry oe : stateOptions) {
650 if (oe.uid.equals(uid)) {
651 stateOptions.remove(oe);
656 public class ShellyChannel {
657 private final ShellyTranslationProvider messages;
658 public String group = "";
659 public String groupLabel = "";
660 public String groupDescription = "";
662 public String channel = "";
663 public String label = "";
664 public String description = "";
665 public String itemType = "";
666 public String typeId = "";
667 public String category = "";
668 public Set<String> tags = new HashSet<>();
669 public @Nullable Unit<?> unit;
670 public Optional<Integer> min = Optional.empty();
671 public Optional<Integer> max = Optional.empty();
672 public Optional<Integer> step = Optional.empty();
673 public Optional<String> pattern = Optional.empty();
675 public ShellyChannel(ShellyTranslationProvider messages, String group, String channel, String typeId,
676 String itemType, String... category) {
677 this.messages = messages;
679 this.channel = channel;
680 this.itemType = itemType;
681 this.typeId = typeId;
683 groupLabel = getText(PREFIX_GROUP + group + ".label");
684 if (groupLabel.startsWith(PREFIX_GROUP)) {
687 groupDescription = getText(PREFIX_GROUP + group + ".description");
688 if (groupDescription.startsWith(PREFIX_GROUP)) {
689 groupDescription = "";
691 label = getText(PREFIX_CHANNEL + typeId.replace(':', '.') + ".label");
692 if (label.startsWith(PREFIX_CHANNEL)) {
695 description = getText(PREFIX_CHANNEL + typeId + ".description");
696 if (description.startsWith(PREFIX_CHANNEL)) {
697 description = ""; // no resource found
701 public String getChanneId() {
702 return group + "#" + channel;
705 public String getGroupLabel() {
706 return getGroupAttribute("group");
709 public String getGroupDescription() {
710 return getGroupAttribute("group");
713 public String getLabel() {
714 return getChannelAttribute("label");
717 public String getDescription() {
718 return getChannelAttribute("description");
721 public boolean getAdvanced() {
722 String attr = getChannelAttribute("advanced");
723 return attr.isEmpty() ? false : Boolean.valueOf(attr);
726 public boolean getReadyOnly() {
727 String attr = getChannelAttribute("readOnly");
728 return attr.isEmpty() ? false : Boolean.valueOf(attr);
731 public String getCategory() {
732 return getChannelAttribute("category");
735 public String getMin() {
736 return getChannelAttribute("min");
739 public String getMax() {
740 return getChannelAttribute("max");
743 public String getStep() {
744 return getChannelAttribute("step");
747 public String getPattern() {
748 return getChannelAttribute("pattern");
751 public String getGroupAttribute(String attribute) {
752 String key = PREFIX_GROUP + group + "." + attribute;
753 String value = messages.getText(key);
754 return !value.equals(key) ? value : "";
757 public String getChannelAttribute(String attribute) {
758 String key = PREFIX_CHANNEL + channel + "." + attribute;
759 String value = messages.getText(key);
760 return !value.equals(key) ? value : "";
763 private String getText(String key) {
764 return messages.get(key);
768 public static class ChannelMap {
769 private final Map<String, ShellyChannel> map = new HashMap<>();
771 private ChannelMap add(ShellyChannel def) {
772 map.put(def.getChanneId(), def);
776 public ShellyChannel get(String channelName) throws IllegalArgumentException {
777 ShellyChannel def = null;
778 if (channelName.contains("#")) {
779 def = map.get(channelName);
784 for (HashMap.Entry<String, ShellyChannel> entry : map.entrySet()) {
785 if (entry.getValue().channel.contains("#" + channelName)) {
786 def = entry.getValue();
792 throw new IllegalArgumentException("Channel definition for " + channelName + " not found!");