[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:
parent
892221ccad
commit
a2084e746a
@ -17,6 +17,7 @@ The binding gets in sync with the next status refresh.
|
||||
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
|
||||
@ -276,6 +277,7 @@ Check the channel definitions for the various devices to see if the device suppo
|
||||
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
|
||||
|
||||
@ -309,7 +311,7 @@ A new alarm will be triggered on a new condition or every 5 minutes if the condi
|
||||
|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
|
||||
|
||||
@ -803,6 +805,7 @@ You can define 2 items (1 Switch, 1 Number) mapping to the same channel, see exa
|
||||
| |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)
|
||||
|
||||
@ -1090,8 +1093,8 @@ when
|
||||
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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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+
|
||||
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
|
||||
|
||||
@ -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
|
||||
if (profile.isMotion) {
|
||||
// handle as status
|
||||
updateChannel(updates, CHANNEL_GROUP_SENSOR, CHANNEL_SENSOR_VIBRATION,
|
||||
value == 1 ? OnOffType.ON : OnOffType.OFF);
|
||||
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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,7 +578,8 @@ public class ShellyBaseHandler extends BaseThingHandler implements ShellyDeviceL
|
||||
*/
|
||||
|
||||
private boolean checkRestarted(ShellySettingsStatus status) {
|
||||
if (profile.isInitialized() && (status.uptime < stats.lastUptime || !profile.status.update.oldVersion.isEmpty()
|
||||
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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,10 +125,12 @@ public class ShellyManagerServlet extends HttpServlet {
|
||||
} else {
|
||||
// binary data
|
||||
byte[] data = (byte[]) output.data;
|
||||
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(),
|
||||
e);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user