[shelly] Vibration event for DW2 (#10618)

* Adapted to new checkstyle

Signed-off-by: Markus Michels <markus7017@gmail.com>

* stylecheck cnages; fix CoIoT update for vibration, url encode user+pw on
"set login credentials"

Signed-off-by: Markus Michels <markus7017@gmail.com>

* #10617 Vibration event added for DW2

Signed-off-by: Markus Michels <markus7017@gmail.com>

* brackets

Signed-off-by: Markus Michels <markus7017@gmail.com>

* some unused stuff/code removed

Signed-off-by: Markus Michels <markus7017@gmail.com>
This commit is contained in:
Markus Michels
2021-05-09 20:21:35 +02:00
committed by GitHub
parent 892221ccad
commit a2084e746a
21 changed files with 119 additions and 177 deletions

View File

@@ -191,8 +191,6 @@ public class ShellyBindingConstants {
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
@@ -337,6 +335,7 @@ public class ShellyBindingConstants {
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";
@@ -364,4 +363,5 @@ public class ShellyBindingConstants {
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
}

View File

@@ -34,7 +34,7 @@ public class ShellyApiException extends Exception {
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);
@@ -117,7 +117,7 @@ public class ShellyApiException extends Exception {
}
private boolean isEmpty() {
return nonNullString(super.getMessage()).equals(NONE);
return NONE.equals(nonNullString(super.getMessage()));
}
private static String nonNullString(@Nullable String s) {

View File

@@ -379,9 +379,6 @@ public class ShellyApiJsonDTO {
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 {
@@ -442,8 +439,6 @@ public class ShellyApiJsonDTO {
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")
@@ -468,7 +463,8 @@ public class ShellyApiJsonDTO {
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")
@@ -565,20 +561,14 @@ public class ShellyApiJsonDTO {
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;
@@ -619,15 +609,6 @@ public class ShellyApiJsonDTO {
@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
@@ -700,8 +681,6 @@ public class ShellyApiJsonDTO {
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;
@@ -735,27 +714,6 @@ public class ShellyApiJsonDTO {
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 {
@@ -791,12 +749,6 @@ public class ShellyApiJsonDTO {
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 {
@@ -804,10 +756,7 @@ public class ShellyApiJsonDTO {
@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
@@ -821,30 +770,11 @@ public class ShellyApiJsonDTO {
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
@@ -853,21 +783,6 @@ public class ShellyApiJsonDTO {
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 {

View File

@@ -45,7 +45,7 @@ import com.google.gson.Gson;
@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
@@ -131,6 +131,7 @@ public class ShellyDeviceProfile {
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;
@@ -184,8 +185,6 @@ public class ShellyDeviceProfile {
}
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);

View File

@@ -246,8 +246,8 @@ public class ShellyHttpApi {
}
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 {

View File

@@ -76,9 +76,6 @@ public class ShellyCoIoTProtocol {
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;
@@ -130,8 +127,10 @@ public class ShellyCoIoTProtocol {
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));
@@ -166,7 +165,7 @@ public class ShellyCoIoTProtocol {
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:

View File

@@ -177,8 +177,15 @@ public class ShellyCoIoTVersion1 extends ShellyCoIoTProtocol implements ShellyCo
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

View File

@@ -103,7 +103,10 @@ public class ShellyCoIoTVersion2 extends ShellyCoIoTProtocol implements ShellyCo
// 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
@@ -316,8 +319,14 @@ public class ShellyCoIoTVersion2 extends ShellyCoIoTProtocol implements ShellyCo
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) {

View File

@@ -133,8 +133,9 @@ public class ShellyCoapHandler implements ShellyCoapListener {
.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);

View File

@@ -115,8 +115,11 @@ public class ShellyDiscoveryParticipant implements MDNSDiscoveryParticipant {
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;
}

View File

@@ -101,8 +101,6 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
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;
@@ -111,6 +109,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
private String localPort = "";
private String lastWakeupReason = "";
private int vibrationFilter = 0;
/**
* Constructor
@@ -274,9 +273,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
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) {
@@ -385,6 +382,12 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
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)) {
@@ -483,7 +486,7 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
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();
}
@@ -575,8 +578,9 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
*/
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;
}
@@ -706,13 +710,10 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
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;
@@ -1195,7 +1196,21 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
}
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() {
@@ -1206,11 +1221,6 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
statusJob = null;
logger.debug("{}: Shelly statusJob stopped", thingName);
}
job = asyncButtonRelease;
if (job != null) {
job.cancel(true);
asyncButtonRelease = null;
}
coap.stop();
profile.initialized = false;

View File

@@ -300,8 +300,6 @@ public class ShellyComponents {
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,
@@ -365,8 +363,6 @@ public class ShellyComponents {
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);

View File

@@ -34,11 +34,9 @@ import org.osgi.service.cm.ConfigurationAdmin;
@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,

View File

@@ -92,7 +92,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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
@@ -116,7 +116,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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)
@@ -137,7 +137,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
}
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";
@@ -147,7 +147,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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);
@@ -176,7 +176,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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 {
@@ -204,8 +204,8 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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 {
@@ -222,7 +222,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
}
break;
case ACTION_RESSTA:
if (!update.equalsIgnoreCase("yes")) {
if (!"yes".equalsIgnoreCase(update)) {
message = getMessage("action.resetsta-info");
actionUrl = buildActionUrl(uid, action);
} else {
@@ -237,8 +237,8 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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 {
@@ -254,8 +254,8 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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 {
@@ -272,7 +272,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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());
@@ -308,7 +308,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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");
}
@@ -332,7 +332,7 @@ public class ShellyManagerActionPage extends ShellyManagerPage {
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) {

View File

@@ -115,7 +115,7 @@ public class ShellyManagerOtaPage extends ShellyManagerPage {
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);
@@ -199,9 +199,9 @@ public class ShellyManagerOtaPage extends ShellyManagerPage {
} 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

View File

@@ -148,7 +148,7 @@ public class ShellyManagerOverviewPage extends ShellyManagerPage {
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";

View File

@@ -63,6 +63,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
/**
* {@link ShellyManagerOtaPage} implements the Shelly Manager's page template
@@ -136,8 +137,10 @@ public class ShellyManagerPage {
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,
@@ -242,7 +245,7 @@ public class ShellyManagerPage {
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,
@@ -414,9 +417,9 @@ public class ShellyManagerPage {
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);
}
}

View File

@@ -125,9 +125,11 @@ public class ShellyManagerServlet extends HttpServlet {
} 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(),

View File

@@ -175,7 +175,6 @@ public class ShellyChannelDefinitions {
.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))
@@ -424,8 +423,6 @@ public class ShellyChannelDefinitions {
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);
}
@@ -564,18 +561,17 @@ public class ShellyChannelDefinitions {
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);
}
}

View File

@@ -52,8 +52,8 @@ import com.google.gson.JsonSyntaxException;
*/
@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
@@ -96,6 +96,7 @@ public class ShellyUtils {
}
}
@SuppressWarnings("unchecked")
private static <T> Class<T> wrap(Class<T> type) {
if (type == int.class) {
return (Class<T>) Integer.class;