Refer to [Advanced Users](doc/AdvancedUsers.md) for more information on openHAB Shelly integration, e.g. firmware update, network communication or log filtering.
Also check out the [Shelly Manager](doc/ShellyManager.md), which
+
- provides detailed information on your Shellys
- helps to diagnose WiFi issues or device instabilities
- includes some common actions and
You could use the Shelly App to set the timing for those events.
If you want to use those events triggering a rule:
+
- If a physical switch is connected to the Shelly use the input channel(`input` or `input1`/`input2`) to trigger a rule
- For a momentary button use the `button` trigger channel as trigger, channels `lastEvent` and `eventCount` will provide details on the event
|BATTERY |Device reported an update to the battery status. |
|TEMP_UNDER |Below "temperature under" threshold |
|TEMP_OVER |Above "temperature over" threshold |
-
+|VIBRATION |A vibration/tamper was detected (DW2 only) |
Refer to section [Full Example:shelly.rules](#shelly-rules) for examples how to catch alarm triggers in openHAB rules
| |lastError |String |yes |Last device error. |
|battery |batteryLevel |Number |yes |Battery Level in % |
| |lowBattery |Switch |yes |Low battery alert (< 20%) |
+|device |alarm |Trigger |yes |Will receive trigger VIBRATION if DW2 detects vibration |
### Shelly Motion (thing-type: shellymotion)
Channel "shelly:shelly25-roller:XXXXXX:device#alarm" triggered
then
if (receivedEvent !== null) { // A (channel) event triggered the rule
- eventSource = receivedEvent.getChannel().asString
- eventType = receivedEvent.getEvent()
+ eventSource = triggeredChannel
+ eventType = receivedEvent
...
}
end
public static final String PROPERTY_UPDATE_NEW_VERS = "updateNewVersion";
public static final String PROPERTY_COAP_DESCR = "coapDeviceDescr";
public static final String PROPERTY_COAP_VERSION = "coapVersion";
- public static final String PROPERTY_STATS_TIMEOUTS = "statsTimeoutErrors";
- public static final String PROPERTY_STATS_TRECOVERED = "statsTimeoutsRecovered";
public static final String PROPERTY_COIOTAUTO = "coiotAutoEnable";
// Relay
public static final String ALARM_TYPE_LOADERR = "LOAD_ERROR";
public static final String ALARM_TYPE_SENSOR_ERROR = "SENSOR_ERROR";
public static final String ALARM_TYPE_LOW_BATTERY = "LOW_BATTERY";
+ public static final String EVENT_TYPE_VIBRATION = "VIBRATION";
// Event types
public static final String EVENT_TYPE_RELAY = "relay";
public static final int UPDATE_MIN_DELAY = 15;// update every x triggers or when a key was pressed
public static final int UPDATE_SETTINGS_INTERVAL_SECONDS = 60; // check for updates every x sec
public static final int HEALTH_CHECK_INTERVAL_SEC = 300; // Health check interval, 5min
+ public static final int VIBRATION_FILTER_SEC = 5; // Absore duplicate vibration events for xx sec
}
private static final long serialVersionUID = -5809459454769761821L;
private ShellyApiResult apiResult = new ShellyApiResult();
- private static String NONE = "none";
+ private static final String NONE = "none";
public ShellyApiException(Exception exception) {
super(exception);
}
private boolean isEmpty() {
- return nonNullString(super.getMessage()).equals(NONE);
+ return NONE.equals(nonNullString(super.getMessage()));
}
private static String nonNullString(@Nullable String s) {
public String pushLongUrl; // to access when roller stopped
@SerializedName("shortpush_url")
public String pushShortUrl; // to access when roller stopped
-
- public Boolean schedule;
- // ArrayList<ShellySettingsScheduleRules> schedule_rules;
}
public static class ShellySettingsDimmer {
public Boolean isValid;
@SerializedName("safety_switch")
public Boolean safetySwitch;
- public Boolean schedule;
- // ArrayList<ShellySettingsScheduleRules> schedule_rules; // not used for now
@SerializedName("obstacle_mode")
public String obstaclMode; // SHELLY_OBSTMODE_
@SerializedName("obstacle_action")
public Boolean ison; // true: output is ON
public Integer brightness;
public Integer transition;
- public String default_state;
+ @SerializedName("default_state")
+ public String defaultState;
@SerializedName("auto_on")
public Double autoOn; // Automatic flip back timer, seconds. Will engage after turning Shelly1 OFF.
@SerializedName("auto_off")
public ShellySensorSleepMode sleepMode; // FW 1.6
@SerializedName("external_power")
public Integer externalPower; // H&T FW 1.6, seems to be the same like charger for the Sense
- public Boolean debug_enable; // FW 1.10+
+ @SerializedName("debug_enable") // FW 1.10+
+ public Boolean debugEnable;
public String timezone;
public Double lat;
public Double lng;
public Boolean tzautodetect;
public String time;
- // @SerializedName("tz_utc_offset")
- // public Integer tzUTCOoffset; // FW 1.6+
- // @SerializedName("tz_dst")
- // public Boolean tzDdst; // FW 1.6+
- // @SerializedName("tz_dst_auto")
- // public Boolean tzDstAuto; // FW 1.6+
- // public Long unixtime; // FW 1.6+
public ShellySettingsHwInfo hwinfo;
public String mode;
@SerializedName("vibration_url")
public String vibrationUrl; // URL reports when DW detects vibration FW 1.6.5+
- // @SerializedName("tilt_enabled")
- // public Boolean tiltEnabled; // Whether tilt monitoring is activated
- // @SerializedName("tilt_calibrated")
- // public Boolean tiltCalibrated; // Whether calibration data is valid
- // @SerializedName("vibration_enabled")
- // public Boolean vibrationEnabled; // Whether vibration monitoring is activated
- // @SerializedName("reverse_open_close")
- // public Boolean reverseOpenClose; // Whether to reverse which position the sensor consideres "open"
-
// Gas FW 1.7
@SerializedName("set_volume")
public Integer volume; // Speaker volume for alarm
public Integer input; // RGBW2 has no JSON array
public ArrayList<ShellyInputState> inputs;
public ArrayList<ShellySettingsLight> lights;
- // @SerializedName("night_mode") // FW 1.5.7+
- // public ShellySettingsNightMode nightMode;
public ArrayList<ShellyShortLightStatus> dimmers;
public ArrayList<ShellySettingsMeter> meters;
public ArrayList<ShellySettingsEMeter> emeters;
public static class ShellySettingsInput {
@SerializedName("btn_type")
public String btnType;
-
- // attributes not yet processed
- // public String name;
- // @SerializedName("btn_reverse")
- // public Integer btnReverse;
- // @SerializedName("btn_on_url")
- // public String btnOnUrl;
- // @SerializedName("btn_off_url")
- // public String btnOffUrl;
- // @SerializedName("shortpush_url")
- // public String shortpushUrl;
- // @SerializedName("longpush_url")
- // public String longpushUrl;
- // @SerializedName("double_shortpush_url")
- // public String doubleShortpushUrl;
- // @SerializedName("triple_shortpush_url")
- // public String tripleShortpushUrl;
- // @SerializedName("shortpush_longpush_url")
- // public String shortpushLongpushUrl;
- // @SerializedName("longpush_shortpush_url")
- // public String longpushShortpushUrl;
}
public static class ShellyControlRelay {
public Boolean ison; // Whether output channel is on or off
public String mode; // color or white - valid only for Bulb and RGBW2 even Dimmer returns it also
public Integer brightness; // brightness: 0.100%
- // @SerializedName("has_timer")
- // public Boolean hasTimer; // Whether a timer is currently armed for this channel
- // @SerializedName("timer_remaining")
- // public Integer timerRemaining;
- // public Integer wgite;
- // public Integer temp; // light temp
}
public static class ShellyStatusRelay {
@SerializedName("wifi_sta")
public ShellySettingsWiFiNetwork wifiSta; // WiFi status
- // public ShellyStatusCloud cloud; // Cloud status
- // public ShellyStatusMqtt mqtt; // mqtt status
public ShellySettingsCoiot coiot; // Firmware 1.6+
- // public String time; // current time
public Integer serial;
public String mac; // MAC
public ArrayList<ShellyShortStatusRelay> relays; // relay status
public Double temperature; // device temp acc. on the selected temp unit
public ShellyStatusSensor.ShellySensorTmp tmp;
-
- @SerializedName("has_update")
- public Boolean hasUpdate; // If a newer firmware version is available
- public ShellySettingsUpdate update; // /status/firmware value
-
- @SerializedName("ram_total")
- public Integer ramTotal; // Total and available amount of system memory in bytes
- @SerializedName("ram_free")
- public Integer ramFree;
- @SerializedName("fs_size")
- public Integer fsSize;
- @SerializedName("fs_free")
- public Integer fsFree; // Total and available amount of file system space in bytes
- public Integer uptime; // econds elapsed since boot
}
public static class ShellyStatusDimmer {
@SerializedName("wifi_sta")
public ShellySettingsWiFiNetwork wifiSta; // WiFi status
- // public ShellyStatusCloud cloud; // Cloud status
- // public ShellyStatusMqtt mqtt; // mqtt status
- public String time; // current time
- public Integer serial;
- public String mac; // MAC
public ArrayList<ShellyShortLightStatus> lights; // relay status
public ArrayList<ShellySettingsMeter> meters; // current meter value
public Boolean loaderror;
public Boolean overload;
-
- @SerializedName("has_update")
- public Boolean hasUpdate; // If a newer firmware version is available
- public ShellySettingsUpdate update; // /status/firmware value
-
- @SerializedName("ram_total")
- public Integer ramTotal; // Total and available amount of system memory in
- // bytes
- @SerializedName("ram_free")
- public Integer ramFree;
- @SerializedName("fs_size")
- public Integer fsSize;
- @SerializedName("fs_free")
- public Integer fsFree; // Total and available amount of file system space in bytes
- public Integer uptime; // seconds elapsed since boot
}
public static class ShellyControlRoller {
@NonNullByDefault
public class ShellyDeviceProfile {
private final Logger logger = LoggerFactory.getLogger(ShellyDeviceProfile.class);
- private final static Pattern VERSION_PATTERN = Pattern.compile("v\\d+\\.\\d+\\.\\d+(-[a-z0-9]*)?");
+ private static final Pattern VERSION_PATTERN = Pattern.compile("v\\d+\\.\\d+\\.\\d+(-[a-z0-9]*)?");
public boolean initialized = false; // true when initialized
extFeatures = version.compare(fwVersion, SHELLY_API_FW_110) >= 0;
discoverable = (settings.discoverable == null) || settings.discoverable;
+ isRoller = mode.equalsIgnoreCase(SHELLY_MODE_ROLLER);
inColor = isLight && mode.equalsIgnoreCase(SHELLY_MODE_COLOR);
numRelays = !isLight ? getInteger(settings.device.numOutputs) : 0;
}
isDimmer = deviceType.equalsIgnoreCase(SHELLYDT_DIMMER) || deviceType.equalsIgnoreCase(SHELLYDT_DIMMER2);
- isRoller = mode.equalsIgnoreCase(SHELLY_MODE_ROLLER);
-
isBulb = thingType.equals(THING_TYPE_SHELLYBULB_STR);
isDuo = thingType.equals(THING_TYPE_SHELLYDUO_STR) || thingType.equals(THING_TYPE_SHELLYVINTAGE_STR)
|| thingType.equals(THING_TYPE_SHELLYDUORGBW_STR);
}
public ShellySettingsLogin setLoginCredentials(String user, String password) throws ShellyApiException {
- return callApi(SHELLY_URL_SETTINGS + "/login?enabled=yes&username=" + user + "&password=" + password,
- ShellySettingsLogin.class);
+ return callApi(SHELLY_URL_SETTINGS + "/login?enabled=yes&username=" + urlEncode(user) + "&password="
+ + urlEncode(password), ShellySettingsLogin.class);
}
public String getCoIoTDescription() throws ShellyApiException {
protected boolean handleStatusUpdate(List<CoIotSensor> sensorUpdates, CoIotDescrSen sen, CoIotSensor s,
Map<String, State> updates, ShellyColorUtils col) {
// Process status information and convert into channel updates
- // Integer rIndex = Integer.parseInt(sen.links) + 1;
- // String rGroup = getProfile().numRelays <= 1 ? CHANNEL_GROUP_RELAY_CONTROL
- // : CHANNEL_GROUP_RELAY_CONTROL + rIndex;
int rIndex = getIdFromBlk(sen);
String rGroup = getProfile().numRelays <= 1 ? CHANNEL_GROUP_RELAY_CONTROL
: CHANNEL_GROUP_RELAY_CONTROL + rIndex;
s.value == 1 ? OnOffType.ON : OnOffType.OFF);
break;
case "vibration": // DW with FW1.6.5+
- updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VIBRATION,
- s.value == 1 ? OnOffType.ON : OnOffType.OFF);
+ if (s.value == 1) {
+ thingHandler.triggerChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ALARM_STATE,
+ EVENT_TYPE_VIBRATION);
+ }
break;
case "luminositylevel": // +
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ILLUM, getStringType(s.valueStr));
updateChannel(updates, CHANNEL_GROUP_COLOR_CONTROL, CHANNEL_COLOR_GAIN,
ShellyColorUtils.toPercent((int) s.value, SHELLY_MIN_GAIN, SHELLY_MAX_GAIN));
break;
- case "sensorerror": // +
+ case "sensorerror":
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ERROR, getStringType(s.valueStr));
break;
default:
toQuantityType(s.value, DIGITS_NONE, Units.DEGREE_ANGLE));
break;
case "vibration": // DW with FW1.6.5+
- updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VIBRATION,
- s.value == 1 ? OnOffType.ON : OnOffType.OFF);
+ if (profile.isMotion) {
+ // handle as status
+ updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VIBRATION,
+ s.value == 1 ? OnOffType.ON : OnOffType.OFF);
+ } else if (s.value == 1) {
+ // handle as event
+ thingHandler.triggerChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ALARM_STATE,
+ EVENT_TYPE_VIBRATION);
+ }
break;
case "temp": // Shelly Bulb
case "colortemperature": // Shelly Duo
// skip, could check against thing mode...
break;
- case "1101": // S, output, 0/1
+ case "1101": // relay_0: output, 0/1
+ case "1201": // relay_1: output, 0/1
+ case "1301": // relay_2: output, 0/1
+ case "1401": // relay_3: output, 0/1
updatePower(profile, updates, rIndex, sen, s, sensorUpdates);
break;
case "1102": // roler_0: S, roller, open/close/stop -> roller state
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_ALARM_STATE, getStringType(s.valueStr));
break;
case "6110": // A, vibration, 0/1, -1=unknown
- updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VIBRATION,
- value == 1 ? OnOffType.ON : OnOffType.OFF);
+ if (profile.isMotion) {
+ // handle as status
+ updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VIBRATION,
+ s.value == 1 ? OnOffType.ON : OnOffType.OFF);
+ } else if (s.value == 1) {
+ // handle as event
+ thingHandler.triggerChannel(CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ALARM, EVENT_TYPE_VIBRATION);
+ }
break;
case "9102": // EV, wakeupEvent, battery/button/periodic/poweron/sensor/ext_power, "unknown"=unknown
if (s.valueArray.size() > 0) {
.setTimeout((long) SHELLY_API_TIMEOUT_MS).useNONs().setEndpoint(coapServer.getEndpoint());
@Nullable
Endpoint endpoint = null;
- if (statusClient != null) {
- endpoint = statusClient.getEndpoint();
+ CoapClient client = statusClient;
+ if (client != null) {
+ endpoint = client.getEndpoint();
}
if ((endpoint == null) || !endpoint.isStarted()) {
logger.warn("{}: Unable to initialize CoAP access (network error)", thingName);
Map<String, Object> properties = new TreeMap<>();
name = service.getName().toLowerCase();
- address = service.getHostAddress();
- if ((address == null) || address.isEmpty()) {
+ String[] hostAddresses = service.getHostAddresses();
+ if ((hostAddresses != null) && (hostAddresses.length > 0)) {
+ address = hostAddresses[0];
+ }
+ if (address.isEmpty()) {
logger.trace("{}: Shelly device discovered with empty IP address (service-name={})", name, service);
return null;
}
private int skipUpdate = 0;
private boolean refreshSettings = false;
- private @Nullable ScheduledFuture<?> asyncButtonRelease;
-
// delay before enabling channel
private final int cacheCount = UPDATE_SETTINGS_INTERVAL_SECONDS / UPDATE_STATUS_INTERVAL_SECONDS;
protected final ShellyChannelCache cache;
private String localPort = "";
private String lastWakeupReason = "";
+ private int vibrationFilter = 0;
/**
* Constructor
logger.debug("{}: Unable to set CoIoT peer: {}", thingName, e.toString());
}
} else if (!devpeer.isEmpty() && !devpeer.equals(ourpeer)) {
- logger.warn("{}: CoIoT peer in device settings does not point this to this host, disabling CoIoT",
- thingName);
- config.eventsCoIoT = autoCoIoT = false;
+ logger.warn("{}: CoIoT peer in device settings does not point this to this host", thingName);
}
}
if (autoCoIoT) {
try {
boolean updated = false;
+ if (vibrationFilter > 0) {
+ vibrationFilter--;
+ logger.debug("{}: Vibration events are absorbed for {}Â more seconds", thingName,
+ vibrationFilter * UPDATE_STATUS_INTERVAL_SECONDS);
+ }
+
skipUpdate++;
ThingStatus thingStatus = getThing().getStatus();
if (refreshSettings || (scheduledUpdates > 0) || (skipUpdate % skipCount == 0)) {
updateStatus(ThingStatus.ONLINE);
// request 3 updates in a row (during the first 2+3*3 sec)
- requestUpdates(profile.alwaysOn ? 3 : 1, channelsCreated == false);
+ requestUpdates(profile.alwaysOn ? 3 : 1, !channelsCreated);
}
restartWatchdog();
}
*/
private boolean checkRestarted(ShellySettingsStatus status) {
- if (profile.isInitialized() && (status.uptime < stats.lastUptime || !profile.status.update.oldVersion.isEmpty()
- && !status.update.oldVersion.equals(profile.status.update.oldVersion))) {
+ if (profile.isInitialized() && profile.alwaysOn /* exclude battery powered devices */
+ && (status.uptime < stats.lastUptime || !profile.status.update.oldVersion.isEmpty()
+ && !status.update.oldVersion.equals(profile.status.update.oldVersion))) {
updateProperties(profile, status);
return true;
}
updateChannel(group, CHANNEL_SENSOR_ILLUM, getStringType(event));
break;
- case SHELLY_EVENT_VIBRATION:
- updateChannel(group, CHANNEL_SENSOR_VIBRATION, OnOffType.ON);
- break;
-
case SHELLY_EVENT_ALARM_MILD: // Shelly Gas
case SHELLY_EVENT_ALARM_HEAVY:
case SHELLY_EVENT_ALARM_OFF:
+ case SHELLY_EVENT_VIBRATION: // DW2
channel = CHANNEL_SENSOR_ALARM_STATE;
payload = event.toUpperCase();
break;
}
public void triggerChannel(String group, String channel, String payload) {
- triggerChannel(mkChannelId(group, channel), payload);
+ String triggerCh = mkChannelId(group, channel);
+ logger.debug("{}: Send event {} to channel {}", thingName, triggerCh, payload);
+ if (EVENT_TYPE_VIBRATION.contentEquals(payload)) {
+ if (vibrationFilter == 0) {
+ vibrationFilter = VIBRATION_FILTER_SEC / UPDATE_STATUS_INTERVAL_SECONDS + 1;
+ logger.debug("{}: Duplicate vibration events will be absorbed for the next {} sec", thingName,
+ vibrationFilter * UPDATE_STATUS_INTERVAL_SECONDS);
+ } else {
+ logger.debug("{}: Vibration event absorbed, {}Â sec remaining", thingName,
+ vibrationFilter * UPDATE_STATUS_INTERVAL_SECONDS);
+ return;
+ }
+ }
+
+ triggerChannel(triggerCh, payload);
}
public void stop() {
statusJob = null;
logger.debug("{}: Shelly statusJob stopped", thingName);
}
- job = asyncButtonRelease;
- if (job != null) {
- job.cancel(true);
- asyncButtonRelease = null;
- }
coap.stop();
profile.initialized = false;
if (sdata.accel != null) {
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TILT,
toQuantityType(getDouble(sdata.accel.tilt.doubleValue()), DIGITS_NONE, Units.DEGREE_ANGLE));
- updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VIBRATION,
- getInteger(sdata.accel.vibration) == 1 ? OnOffType.ON : OnOffType.OFF);
}
if (sdata.flood != null) {
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_FLOOD,
updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_MOTION_TS,
getTimestamp(getString(profile.settings.timezone), timestamp));
}
- updated |= thingHandler.updateChannel(CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VIBRATION,
- getOnOff(sdata.sensor.vibration));
}
updated |= thingHandler.updateInputs(status);
@NonNullByDefault
public class ShellyManager {
private final Map<String, ShellyManagerPage> pages = new LinkedHashMap<>();
- private final ShellyHandlerFactory handlerFactory;
public ShellyManager(ConfigurationAdmin configurationAdmin, ShellyTranslationProvider translationProvider,
HttpClient httpClient, String localIp, int localPort, ShellyHandlerFactory handlerFactory) {
- this.handlerFactory = handlerFactory;
pages.put(SHELLY_MGR_OVERVIEW_URI, new ShellyManagerOverviewPage(configurationAdmin, translationProvider,
httpClient, localIp, localPort, handlerFactory));
pages.put(SHELLY_MGR_ACTION_URI, new ShellyManagerActionPage(configurationAdmin, translationProvider,
refreshTimer = 3;
break;
case ACTION_RESTART:
- if (update.equalsIgnoreCase("yes")) {
+ if ("yes".equalsIgnoreCase(update)) {
message = getMessageP("action.restart.info", MCINFO);
actionButtonLabel = "Ok";
new Thread(() -> { // schedule asynchronous reboot
break;
}
- if (!update.equalsIgnoreCase("yes")) {
+ if (!"yes".equalsIgnoreCase(update)) {
ShellySettingsLogin status = api.getLoginSettings();
message = getMessage("action.protect.status", getBool(status.enabled) ? "enabled" : "disabled",
status.username)
}
String peer = getString(profile.settings.coiot.peer);
- boolean mcast = peer.isEmpty() || peer.equalsIgnoreCase(SHELLY_COIOT_MCAST);
+ boolean mcast = peer.isEmpty() || SHELLY_COIOT_MCAST.equalsIgnoreCase(peer);
String newPeer = mcast ? localIp + ":" + ShellyCoapJSonDTO.COIOT_PORT : SHELLY_COIOT_MCAST;
String displayPeer = mcast ? newPeer : "Multicast";
break;
}
- if (!update.equalsIgnoreCase("yes")) {
+ if (!"yes".equalsIgnoreCase(update)) {
message = getMessageP("coiot.current-peer", MCMESSAGE, mcast ? "Multicast" : peer)
+ getMessageP("coiot.new-peer", MCINFO, displayPeer)
+ getMessageP(mcast ? "coiot.mode-peer" : "coiot.mode-mcast", MCMESSAGE);
refreshTimer = 20;
break;
case ACTION_RESET:
- if (!update.equalsIgnoreCase("yes")) {
+ if (!"yes".equalsIgnoreCase(update)) {
message = getMessageP("action.reset.warning", MCWARNING, serviceName);
actionUrl = buildActionUrl(uid, action);
} else {
break;
case ACTION_ENDEBUG:
case ACTION_DISDEBUG:
- boolean enable = action.equalsIgnoreCase(ACTION_ENDEBUG);
- if (!update.equalsIgnoreCase("yes")) {
+ boolean enable = ACTION_ENDEBUG.equalsIgnoreCase(action);
+ if (!"yes".equalsIgnoreCase(update)) {
message = getMessage(enable ? "action.debug-enable" : "action.debug-disable");
actionUrl = buildActionUrl(uid, action);
} else {
}
break;
case ACTION_RESSTA:
- if (!update.equalsIgnoreCase("yes")) {
+ if (!"yes".equalsIgnoreCase(update)) {
message = getMessage("action.resetsta-info");
actionUrl = buildActionUrl(uid, action);
} else {
break;
case ACTION_ENWIFIREC:
case ACTION_DISWIFIREC:
- enable = action.equalsIgnoreCase(ACTION_ENWIFIREC);
- if (!update.equalsIgnoreCase("yes")) {
+ enable = ACTION_ENWIFIREC.equalsIgnoreCase(action);
+ if (!"yes".equalsIgnoreCase(update)) {
message = getMessage(enable ? "action.setwifirec-enable" : "action.setwifirec-disable");
actionUrl = buildActionUrl(uid, action);
} else {
case ACTION_ENAPROAMING:
case ACTION_DISAPROAMING:
- enable = action.equalsIgnoreCase(ACTION_ENAPROAMING);
- if (!update.equalsIgnoreCase("yes")) {
+ enable = ACTION_ENAPROAMING.equalsIgnoreCase(action);
+ if (!"yes".equalsIgnoreCase(update)) {
message = getMessage(enable ? "action.aproaming-enable" : "action.aproaming-disable");
actionUrl = buildActionUrl(uid, action);
} else {
case ACTION_GETDEB:
case ACTION_GETDEB1:
try {
- message = api.getDebugLog(action.equalsIgnoreCase(ACTION_GETDEB) ? "log" : "log1");
+ message = api.getDebugLog(ACTION_GETDEB.equalsIgnoreCase(action) ? "log" : "log1");
message = message.replaceAll("[\r]", "").replaceAll("[\r\n]", "<br>");
} catch (ShellyApiException e) {
message = getMessage("action.getdebug-failed", e.toString());
if ((profile.settings.coiot != null) && (profile.settings.coiot.peer != null) && !profile.isMotion) {
boolean mcast = profile.settings.coiot.peer.isEmpty()
- || profile.settings.coiot.peer.equalsIgnoreCase(SHELLY_COIOT_MCAST);
+ || SHELLY_COIOT_MCAST.equalsIgnoreCase(profile.settings.coiot.peer);
list.put(mcast ? ACTION_SETCOIOT_PEER : ACTION_SETCOIOT_MCAST,
mcast ? "Set CoIoT Peer Mode" : "Set CoIoT Multicast Mode");
}
list.put(ACTION_RESET, "-Factory Reset");
if (profile.extFeatures) {
list.put(ACTION_OTACHECK, "Check for Update");
- boolean debug_enable = getBool(profile.settings.debug_enable);
+ boolean debug_enable = getBool(profile.settings.debugEnable);
list.put(!debug_enable ? ACTION_ENDEBUG : ACTION_DISDEBUG,
!debug_enable ? "Enable Debug" : "Disable Debug");
if (debug_enable) {
properties.put(ATTRIBUTE_UPDATE_URL, "http://" + getDeviceIp(properties) + "/ota?" + updateUrl);
properties.put(URLPARM_CONNECTION, connection);
- if (update.equalsIgnoreCase("yes")) {
+ if ("yes".equalsIgnoreCase(update)) {
// do the update
th.setThingOffline(ThingStatusDetail.FIRMWARE_UPDATING, "offline.status-error-fwupgrade");
html += loadHTML(FWUPDATE2_HTML, properties);
} else {
// convert prod/beta to full url
FwRepoEntry fw = getFirmwareRepoEntry(deviceType, mode);
- String url = getString(prod ? fw.url : fw.beta_url);
- logger.debug("ShellyManager: Map {} release to url {}, version {}", url,
- prod ? fw.url : fw.beta_url, prod ? fw.version : fw.beta_ver);
+ String url = getString(prod ? fw.url : fw.betaUrl);
+ logger.debug("ShellyManager: Map {} release to url {}, version {}", url, prod ? fw.url : fw.betaUrl,
+ prod ? fw.version : fw.betaVer);
return url;
}
default: // Update from firmware archive
html += "\t\t\t\t\t<option value=\"" + updateUrl + "&" + URLPARM_VERSION + "=" + FWPROD + "\">Release "
+ pVersion + "</option>\n";
}
- bVersion = extractFwVersion(fw.beta_ver);
+ bVersion = extractFwVersion(fw.betaVer);
if (!bVersion.isEmpty()) {
html += "\t\t\t\t\t<option value=\"" + updateUrl + "&" + URLPARM_VERSION + "=" + FWBETA + "\">Beta "
+ bVersion + "</option>\n";
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
+import com.google.gson.annotations.SerializedName;
/**
* {@link ShellyManagerOtaPage} implements the Shelly Manager's page template
public @Nullable String url; // prod
public @Nullable String version;
- public @Nullable String beta_url; // beta version if avilable
- public @Nullable String beta_ver;
+ @SerializedName("beta_url")
+ public @Nullable String betaUrl; // beta version if avilable
+ @SerializedName("beta_ver")
+ public @Nullable String betaVer;
}
public ShellyManagerPage(ConfigurationAdmin configurationAdmin, ShellyTranslationProvider translationProvider,
addAttribute(properties, th, CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_ALARM);
addAttribute(properties, th, CHANNEL_GROUP_DEV_STATUS, CHANNEL_DEVST_CHARGER);
- properties.put(ATTRIBUTE_DEBUG_MODE, getOption(profile.settings.debug_enable));
+ properties.put(ATTRIBUTE_DEBUG_MODE, getOption(profile.settings.debugEnable));
properties.put(ATTRIBUTE_DISCOVERABLE, String.valueOf(getBool(profile.settings.discoverable)));
properties.put(ATTRIBUTE_WIFI_RECOVERY, String.valueOf(getBool(profile.settings.wifiRecoveryReboot)));
properties.put(ATTRIBUTE_APR_MODE,
fw.url = url;
logger.debug("ShellyManager: Release Split-URL for device type {} is {}", deviceType, url);
}
- url = substringBefore(fw.beta_url, ".zip") + "-" + mode + ".zip";
+ url = substringBefore(fw.betaUrl, ".zip") + "-" + mode + ".zip";
if (testUrl(url)) {
- fw.beta_url = url;
+ fw.betaUrl = url;
logger.debug("ShellyManager: Beta Split-URL for device type {} is {}", deviceType, url);
}
}
} else {
// binary data
byte[] data = (byte[]) output.data;
- response.setContentLength(data.length);
- bin = response.getOutputStream();
- bin.write(data, 0, data.length);
+ if (data != null) {
+ response.setContentLength(data.length);
+ bin = response.getOutputStream();
+ bin.write(data, 0, data.length);
+ }
}
} catch (ShellyApiException | RuntimeException e) {
logger.debug("{}: Exception uri={}, parameters={}", className, path, request.getParameterMap().toString(),
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VOLTAGE, "sensorADC", ITEMT_VOLT))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_CONTACT, "sensorContact", ITEMT_CONTACT))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_SSTATE, "sensorState", ITEMT_STRING))
- .add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_VIBRATION, "sensorVibration", ITEMT_SWITCH))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_TILT, "sensorTilt", ITEMT_ANGLE))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION, "sensorMotion", ITEMT_SWITCH))
.add(new ShellyChannel(m, CHGR_SENSOR, CHANNEL_SENSOR_MOTION_TS, "motionTimestamp", ITEMT_DATETIME))
CHANNEL_SENSOR_VIBRATION);
}
if (sdata.accel != null) { // DW2
- addChannel(thing, newChannels, sdata.accel.vibration != null, CHANNEL_GROUP_SENSOR,
- CHANNEL_SENSOR_VIBRATION);
addChannel(thing, newChannels, sdata.accel.tilt != null, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_TILT);
}
public String getGroupAttribute(String attribute) {
String key = PREFIX_GROUP + group + "." + attribute;
String value = messages.getText(key);
- return value != null && !value.equals(key) ? value : "";
+ return !value.equals(key) ? value : "";
}
public String getChannelAttribute(String attribute) {
String key = PREFIX_CHANNEL + channel + "." + attribute;
String value = messages.getText(key);
- return value != null && !value.equals(key) ? value : "";
+ return !value.equals(key) ? value : "";
}
private String getText(String key) {
- String text = messages.get(key);
- return text != null ? text : "";
+ return messages.get(key);
}
}
*/
@NonNullByDefault
public class ShellyUtils {
- private final static String PRE = "Unable to create object of type ";
- public final static DateTimeFormatter DATE_TIME = DateTimeFormatter.ofPattern(DateTimeType.DATE_PATTERN);
+ private static final String PRE = "Unable to create object of type ";
+ public static final DateTimeFormatter DATE_TIME = DateTimeFormatter.ofPattern(DateTimeType.DATE_PATTERN);
public static <T> T fromJson(Gson gson, @Nullable String json, Class<T> classOfT) throws ShellyApiException {
@Nullable
}
}
+ @SuppressWarnings("unchecked")
private static <T> Class<T> wrap(Class<T> type) {
if (type == int.class) {
return (Class<T>) Integer.class;