[somfytahoma] Fix getting history events (#18323)
Signed-off-by: Ondrej Pecta <opecta@gmail.com>pull/18348/head
parent
72682766b3
commit
b01d8225b6
|
@ -49,7 +49,7 @@ Binding itself doesn't require specific configuration.
|
|||
| JA-80/JA-100/JA-100F | lastEventTime | DateTime | the time of the last event |
|
||||
| JA-80/JA-100/JA-100F | lastCheckTime | DateTime | the time of the last checking |
|
||||
| JA-80/JA-100/JA-100F | alarm | N/A | the alarm trigger, might fire ALARM or TAMPER events |
|
||||
| JA-100/JA-100F | lastEventSection | String | the section of the last event |
|
||||
| JA-80/JA-100/JA-100F | lastEventSection | String | the section of the last event |
|
||||
| JA-100 | state_%nr% | String | the section %nr% status/control |
|
||||
| JA-100 | pgm_%nr% | Switch | the PG switch %nr% status/control |
|
||||
| JA-100 | thermometer_%nr% | Number:Temperature | the thermometer %nr% value |
|
||||
|
|
|
@ -55,13 +55,16 @@ public class JablotronBindingConstants {
|
|||
|
||||
// Constants
|
||||
public static final String JABLOTRON_API_URL = "https://api.jablonet.net/api/2.2/";
|
||||
public static final String AGENT = "net.jablonet/8.3.5.3331 (iPhone 14 Pro Max; iOS 17.4; )";
|
||||
public static final int TIMEOUT_SEC = 10;
|
||||
public static final String JABLOTRON_GQL_URL = "https://graph.jablotron.cloud/graphql";
|
||||
public static final String APP_VERSION = "8.6.1.3887";
|
||||
public static final String AGENT = "net.jablonet/" + APP_VERSION;
|
||||
public static final int TIMEOUT_SEC = 15;
|
||||
public static final int TIMEOUT_LIMIT = 3;
|
||||
public static final String SYSTEM = "openHAB";
|
||||
public static final String VENDOR = "JABLOTRON:Jablotron";
|
||||
public static final String CLIENT_VERSION = "MYJ-PUB-IOS-8.3.5.3331";
|
||||
public static final String CLIENT_DEVICE = "Apple|iPhone 14 Pro Max|17.4";
|
||||
public static final String CLIENT_VERSION = "MYJ-PUB-IOS-" + APP_VERSION;
|
||||
public static final String APPLICATION_JSON = "application/json";
|
||||
public static final String MULTIPART_MIXED = "multipart/mixed;deferSpec=20220824";
|
||||
public static final String WWW_FORM_URLENCODED = "application/x-www-form-urlencoded; charset=UTF-8";
|
||||
public static final String AUTHENTICATION_CHALLENGE = "Authentication challenge without WWW-Authenticate header";
|
||||
public static final String PROPERTY_SERVICE_ID = "serviceId";
|
||||
|
|
|
@ -17,7 +17,6 @@ import static org.openhab.binding.jablotron.JablotronBindingConstants.*;
|
|||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -72,7 +71,7 @@ public abstract class JablotronAlarmHandler extends BaseThingHandler {
|
|||
protected @Nullable ScheduledFuture<?> future = null;
|
||||
|
||||
protected @Nullable ExpiringCache<JablotronDataUpdateResponse> dataCache;
|
||||
protected ExpiringCache<List<JablotronHistoryDataEvent>> eventCache;
|
||||
protected ExpiringCache<JablotronHistoryDataEvent> eventCache;
|
||||
|
||||
public JablotronAlarmHandler(Thing thing, String alarmName) {
|
||||
super(thing);
|
||||
|
@ -186,20 +185,19 @@ public abstract class JablotronAlarmHandler extends BaseThingHandler {
|
|||
logger.debug("Error during alarm status update: {}", dataUpdate.getErrorMessage());
|
||||
}
|
||||
|
||||
List<JablotronHistoryDataEvent> events = sendGetEventHistory();
|
||||
if (events != null && !events.isEmpty()) {
|
||||
JablotronHistoryDataEvent event = events.get(0);
|
||||
JablotronHistoryDataEvent event = sendGetEventHistory();
|
||||
if (event != null) {
|
||||
updateLastEvent(event);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected @Nullable List<JablotronHistoryDataEvent> sendGetEventHistory() {
|
||||
protected @Nullable JablotronHistoryDataEvent sendGetEventHistory() {
|
||||
return sendGetEventHistory(alarmName);
|
||||
}
|
||||
|
||||
private @Nullable List<JablotronHistoryDataEvent> sendGetEventHistory(String alarm) {
|
||||
private @Nullable JablotronHistoryDataEvent sendGetEventHistory(String alarm) {
|
||||
JablotronBridgeHandler handler = getBridgeHandler();
|
||||
if (handler != null) {
|
||||
return handler.sendGetEventHistory(getThing(), alarm);
|
||||
|
@ -208,7 +206,7 @@ public abstract class JablotronAlarmHandler extends BaseThingHandler {
|
|||
}
|
||||
|
||||
protected void updateLastEvent(JablotronHistoryDataEvent event) {
|
||||
updateState(CHANNEL_LAST_EVENT_TIME, new DateTimeType(getZonedDateTime(event.getDate())));
|
||||
updateState(CHANNEL_LAST_EVENT_TIME, new DateTimeType(Instant.parse(event.getDate())));
|
||||
updateState(CHANNEL_LAST_EVENT, new StringType(event.getEventText()));
|
||||
updateState(CHANNEL_LAST_EVENT_CLASS, new StringType(event.getIconType()));
|
||||
updateState(CHANNEL_LAST_EVENT_INVOKER, new StringType(event.getInvokerName()));
|
||||
|
@ -220,12 +218,11 @@ public abstract class JablotronAlarmHandler extends BaseThingHandler {
|
|||
}
|
||||
|
||||
protected void updateEventChannel(String channel) {
|
||||
List<JablotronHistoryDataEvent> events = eventCache.getValue();
|
||||
if (events != null && !events.isEmpty()) {
|
||||
JablotronHistoryDataEvent event = events.get(0);
|
||||
JablotronHistoryDataEvent event = eventCache.getValue();
|
||||
if (event != null) {
|
||||
switch (channel) {
|
||||
case CHANNEL_LAST_EVENT_TIME:
|
||||
updateState(CHANNEL_LAST_EVENT_TIME, new DateTimeType(getZonedDateTime(event.getDate())));
|
||||
updateState(CHANNEL_LAST_EVENT_TIME, new DateTimeType(Instant.parse(event.getDate())));
|
||||
break;
|
||||
case CHANNEL_LAST_EVENT:
|
||||
updateState(CHANNEL_LAST_EVENT, new StringType(event.getEventText()));
|
||||
|
@ -243,11 +240,6 @@ public abstract class JablotronAlarmHandler extends BaseThingHandler {
|
|||
}
|
||||
}
|
||||
|
||||
public ZonedDateTime getZonedDateTime(String date) {
|
||||
return ZonedDateTime.parse(date.substring(0, 22) + ":" + date.substring(22, 24),
|
||||
DateTimeFormatter.ISO_DATE_TIME);
|
||||
}
|
||||
|
||||
protected @Nullable JablotronControlResponse sendUserCode(String section, String key, String status, String code) {
|
||||
JablotronBridgeHandler handler = getBridgeHandler();
|
||||
if (handler != null) {
|
||||
|
|
|
@ -32,10 +32,10 @@ import org.eclipse.jetty.http.HttpHeader;
|
|||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.jablotron.internal.config.JablotronBridgeConfig;
|
||||
import org.openhab.binding.jablotron.internal.discovery.JablotronDiscoveryService;
|
||||
import org.openhab.binding.jablotron.internal.model.JablotronAccessTokenResponse;
|
||||
import org.openhab.binding.jablotron.internal.model.JablotronControlResponse;
|
||||
import org.openhab.binding.jablotron.internal.model.JablotronDataUpdateResponse;
|
||||
import org.openhab.binding.jablotron.internal.model.JablotronDiscoveredService;
|
||||
import org.openhab.binding.jablotron.internal.model.JablotronGetEventHistoryResponse;
|
||||
import org.openhab.binding.jablotron.internal.model.JablotronGetServiceResponse;
|
||||
import org.openhab.binding.jablotron.internal.model.JablotronHistoryDataEvent;
|
||||
import org.openhab.binding.jablotron.internal.model.JablotronLoginResponse;
|
||||
|
@ -54,6 +54,9 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
|
||||
/**
|
||||
|
@ -71,6 +74,8 @@ public class JablotronBridgeHandler extends BaseBridgeHandler {
|
|||
|
||||
final HttpClient httpClient;
|
||||
|
||||
private String accessToken = "";
|
||||
|
||||
private @Nullable ScheduledFuture<?> future = null;
|
||||
|
||||
/**
|
||||
|
@ -169,14 +174,47 @@ public class JablotronBridgeHandler extends BaseBridgeHandler {
|
|||
return sendMessage(url, urlParameters, classOfT, WWW_FORM_URLENCODED, true);
|
||||
}
|
||||
|
||||
private @Nullable String sendGQLMessage(String url, String urlParameters) {
|
||||
String line = "";
|
||||
try {
|
||||
logger.trace("Request: {} with data: {}", url, urlParameters);
|
||||
ContentResponse resp = createGQLRequest(url)
|
||||
.content(new StringContentProvider(urlParameters), APPLICATION_JSON).send();
|
||||
|
||||
line = resp.getContentAsString();
|
||||
logger.trace("Response: {}", line);
|
||||
return line;
|
||||
} catch (TimeoutException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Timeout during calling url: " + url);
|
||||
} catch (InterruptedException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Interrupt during calling url: " + url);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (JsonSyntaxException e) {
|
||||
logger.debug("Invalid JSON received: {}", line);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Syntax error during calling url: " + url);
|
||||
} catch (ExecutionException e) {
|
||||
if (e.getMessage().contains(AUTHENTICATION_CHALLENGE)) {
|
||||
relogin();
|
||||
return null;
|
||||
}
|
||||
logger.debug("Error during calling url: {}", url, e);
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Error during calling url: " + url);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable <T> T sendMessage(String url, String urlParameters, Class<T> classOfT, String encoding,
|
||||
boolean relogin) {
|
||||
String line = "";
|
||||
try {
|
||||
logger.trace("Request: {} with data: {}", url, urlParameters);
|
||||
ContentResponse resp = createRequest(url).content(new StringContentProvider(urlParameters), encoding)
|
||||
.send();
|
||||
|
||||
logger.trace("Request: {} with data: {}", url, urlParameters);
|
||||
line = resp.getContentAsString();
|
||||
logger.trace("Response: {}", line);
|
||||
return gson.fromJson(line, classOfT);
|
||||
|
@ -212,13 +250,31 @@ public class JablotronBridgeHandler extends BaseBridgeHandler {
|
|||
JablotronLoginResponse response = sendJsonMessage(url, urlParameters, JablotronLoginResponse.class, false);
|
||||
|
||||
if (response == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Null login response");
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.getHttpCode() != 200) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Http error: " + response.getHttpCode());
|
||||
"Login http error: " + response.getHttpCode());
|
||||
return;
|
||||
}
|
||||
|
||||
url = JABLOTRON_API_URL + "accessTokenGet.json";
|
||||
urlParameters = "{ \"force-renew\": true }";
|
||||
JablotronAccessTokenResponse token_response = sendJsonMessage(url, urlParameters,
|
||||
JablotronAccessTokenResponse.class, false);
|
||||
|
||||
if (token_response == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Null get access token response");
|
||||
return;
|
||||
}
|
||||
|
||||
if (token_response.getHttpCode() != 200) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"Get access token http error: " + response.getHttpCode());
|
||||
} else {
|
||||
accessToken = token_response.getData().getAccessToken();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
}
|
||||
|
@ -287,8 +343,7 @@ public class JablotronBridgeHandler extends BaseBridgeHandler {
|
|||
return response;
|
||||
}
|
||||
|
||||
protected @Nullable List<JablotronHistoryDataEvent> sendGetEventHistory(Thing th, String alarm) {
|
||||
String url = JABLOTRON_API_URL + alarm + "/eventHistoryGet.json";
|
||||
protected @Nullable JablotronHistoryDataEvent sendGetEventHistory(Thing th, String alarm) {
|
||||
JablotronAlarmHandler handler = (JablotronAlarmHandler) th.getHandler();
|
||||
|
||||
if (handler == null) {
|
||||
|
@ -296,18 +351,37 @@ public class JablotronBridgeHandler extends BaseBridgeHandler {
|
|||
return null;
|
||||
}
|
||||
|
||||
String urlParameters = "{\"limit\":1, \"service-id\":" + handler.thingConfig.getServiceId() + "}";
|
||||
JablotronGetEventHistoryResponse response = sendJsonMessage(url, urlParameters,
|
||||
JablotronGetEventHistoryResponse.class);
|
||||
String urlParameters = "{\"operationName\":\"GetEvents\",\"query\":\"query GetEvents($cloudEntityIds: [CloudEntityID!]!, $pagination: Pagination, $lang: String!, $filter: EventsFilter, $eventIds: [ID!]!) { forEndUser { __typename events { __typename events(sources: $cloudEntityIds, pagination: $pagination, filter: $filter) { __typename edges { __typename node { __typename ...EventsFragment } } pageInfo { __typename hasNextPage endCursor startCursor } } batchEvents(sources: $cloudEntityIds, eventIds: $eventIds) { __typename ...EventsFragment } } } }\\nfragment EventsAttachementFragment on EventsAttachment { __typename files { __typename name mimeType downloadUrl } images { __typename name mimeType downloadUrl available widthPx heightPx } videos { __typename name mimeType downloadUrl duration } id type occurredAt }\\nfragment EventsEventFragment on EventsEvent { __typename id name { __typename translation(lang: $lang) } type occurredAt sources { __typename cloudEntityId } invokers { __typename ...EventsInvokerFragment } subjects { __typename ...EventsSubjectFragment } icon }\\nfragment EventsFragment on EventsEvent { __typename ...EventsEventFragment attachments { __typename ...EventsAttachementFragment } childEvents { __typename id name { __typename translation(lang: $lang) } type occurredAt sources { __typename cloudEntityId } invokers { __typename ...EventsInvokerFragment } subjects { __typename ...EventsSubjectFragment } icon attachments { __typename ...EventsAttachementFragment } } }\\nfragment EventsInvokerFragment on EventsInvoker { __typename cloudEntityId defaultName { __typename translation(lang: $lang) } name }\\nfragment EventsSubjectFragment on EventsSubject { __typename name cloudEntityId defaultName { __typename translation(lang: $lang) } }\",\"variables\":{\"cloudEntityIds\":[\"SERVICE_"
|
||||
+ alarm + ":" + handler.thingConfig.getServiceId() + "\"],\"eventIds\":[],\"lang\":\""
|
||||
+ bridgeConfig.getLang() + "\",\"pagination\":{\"first\":1}}}";
|
||||
|
||||
String response = sendGQLMessage(JABLOTRON_GQL_URL, urlParameters);
|
||||
if (response == null) {
|
||||
logger.debug("Null response while getting event history");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (200 != response.getHttpCode()) {
|
||||
logger.debug("Got error while getting history with http code: {}", response.getHttpCode());
|
||||
}
|
||||
return response.getData().getEvents();
|
||||
return parseEventHistoryResponse(response);
|
||||
}
|
||||
|
||||
private @Nullable JablotronHistoryDataEvent parseEventHistoryResponse(String response) {
|
||||
JsonObject jsonObject = JsonParser.parseString(response).getAsJsonObject();
|
||||
JsonArray edges = jsonObject.getAsJsonObject("data").getAsJsonObject("forEndUser").getAsJsonObject("events")
|
||||
.getAsJsonObject("events").getAsJsonArray("edges");
|
||||
|
||||
JsonObject node = edges.get(0).getAsJsonObject().getAsJsonObject("node").getAsJsonObject();
|
||||
|
||||
JsonObject invoker = node.getAsJsonArray("invokers").get(0).getAsJsonObject();
|
||||
JsonObject subject = node.getAsJsonArray("subjects").get(0).getAsJsonObject();
|
||||
|
||||
JablotronHistoryDataEvent event = new JablotronHistoryDataEvent();
|
||||
event.setIconType(node.get("icon").getAsString());
|
||||
event.setEventText(node.getAsJsonObject("name").get("translation").getAsString());
|
||||
event.setDate(node.get("occurredAt").getAsString());
|
||||
event.setSectionName(subject.getAsJsonObject("defaultName").get("translation").getAsString());
|
||||
event.setInvokerName(invoker.getAsJsonObject("defaultName").get("translation").getAsString());
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
protected @Nullable JablotronDataUpdateResponse sendGetStatusRequest(Thing th) {
|
||||
|
@ -399,8 +473,16 @@ public class JablotronBridgeHandler extends BaseBridgeHandler {
|
|||
private Request createRequest(String url) {
|
||||
return httpClient.newRequest(url).method(HttpMethod.POST).header(HttpHeader.ACCEPT, APPLICATION_JSON)
|
||||
.header(HttpHeader.ACCEPT_LANGUAGE, bridgeConfig.getLang()).header(HttpHeader.ACCEPT_ENCODING, "*")
|
||||
.header("x-vendor-id", VENDOR).header("x-client-version", CLIENT_VERSION)
|
||||
.header("x-client-device", CLIENT_DEVICE).agent(AGENT).timeout(TIMEOUT_SEC, TimeUnit.SECONDS);
|
||||
.header("x-vendor-id", VENDOR).header("x-client-version", CLIENT_VERSION).agent(AGENT)
|
||||
.timeout(TIMEOUT_SEC, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private Request createGQLRequest(String url) {
|
||||
return httpClient.newRequest(url).method(HttpMethod.POST).accept(MULTIPART_MIXED, APPLICATION_JSON)
|
||||
.header(HttpHeader.AUTHORIZATION, "Bearer " + accessToken)
|
||||
.header(HttpHeader.ACCEPT_LANGUAGE, bridgeConfig.getLang())
|
||||
.header(HttpHeader.ACCEPT_ENCODING, "gzip, deflate, br").agent(AGENT)
|
||||
.timeout(TIMEOUT_SEC, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void relogin() {
|
||||
|
|
|
@ -198,9 +198,8 @@ public class JablotronJa100FHandler extends JablotronAlarmHandler {
|
|||
}
|
||||
|
||||
// update events
|
||||
List<JablotronHistoryDataEvent> events = sendGetEventHistory();
|
||||
if (events != null && !events.isEmpty()) {
|
||||
JablotronHistoryDataEvent event = events.get(0);
|
||||
JablotronHistoryDataEvent event = sendGetEventHistory();
|
||||
if (event != null) {
|
||||
updateLastEvent(event);
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -12,22 +12,28 @@
|
|||
*/
|
||||
package org.openhab.binding.jablotron.internal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link JablotronHistoryData} class defines the data object for the
|
||||
* getEventHistory response
|
||||
* The {@link JablotronAccessTokenData} class defines the data object for access token
|
||||
*
|
||||
* @author Ondrej Pecta - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class JablotronHistoryData {
|
||||
List<JablotronHistoryDataEvent> events = new ArrayList<>();
|
||||
public class JablotronAccessTokenData {
|
||||
@SerializedName("access-token")
|
||||
private String accessToken = "";
|
||||
|
||||
public List<JablotronHistoryDataEvent> getEvents() {
|
||||
return events;
|
||||
@SerializedName("access-token-expiration")
|
||||
private String accessTokenExpiration = "";
|
||||
|
||||
public String getAccessToken() {
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
public String getAccessTokenExpiration() {
|
||||
return accessTokenExpiration;
|
||||
}
|
||||
}
|
|
@ -17,24 +17,22 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link JablotronGetEventHistoryResponse} class defines the response for the
|
||||
* getEventHistory operation
|
||||
* The {@link JablotronAccessTokenResponse} class defines the get access token call
|
||||
* response
|
||||
*
|
||||
* @author Ondrej Pecta - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class JablotronGetEventHistoryResponse {
|
||||
|
||||
public class JablotronAccessTokenResponse {
|
||||
@SerializedName("http-code")
|
||||
int httpCode = -1;
|
||||
|
||||
JablotronHistoryData data = new JablotronHistoryData();
|
||||
private int httpCode = -1;
|
||||
private JablotronAccessTokenData data = new JablotronAccessTokenData();
|
||||
|
||||
public int getHttpCode() {
|
||||
return httpCode;
|
||||
}
|
||||
|
||||
public JablotronHistoryData getData() {
|
||||
public JablotronAccessTokenData getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -57,4 +57,24 @@ public class JablotronHistoryDataEvent {
|
|||
public String getSectionName() {
|
||||
return sectionName;
|
||||
}
|
||||
|
||||
public void setIconType(String iconType) {
|
||||
this.iconType = iconType;
|
||||
}
|
||||
|
||||
public void setEventText(String eventText) {
|
||||
this.eventText = eventText;
|
||||
}
|
||||
|
||||
public void setInvokerName(String invokerName) {
|
||||
this.invokerName = invokerName;
|
||||
}
|
||||
|
||||
public void setSectionName(String sectionName) {
|
||||
this.sectionName = sectionName;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,15 @@
|
|||
<channel id="lastEventClass" typeId="lastEventClass"/>
|
||||
<channel id="lastEventInvoker" typeId="lastEventInvoker"/>
|
||||
<channel id="lastEventTime" typeId="lastEventTime"/>
|
||||
<channel id="lastEventSection" typeId="lastEventSection"/>
|
||||
<channel id="lastCheckTime" typeId="lastCheckTime"/>
|
||||
<channel id="alarm" typeId="alarm"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="thingTypeVersion">1</property>
|
||||
</properties>
|
||||
|
||||
<config-description-ref uri="thing-type:jablotron:device"/>
|
||||
</thing-type>
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<update:update-descriptions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:update="https://openhab.org/schemas/update-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/update-description/v1.0.0 https://openhab.org/schemas/update-description-1.0.0.xsd">
|
||||
|
||||
<thing-type uid="jablotron:oasis">
|
||||
<instruction-set targetVersion="1">
|
||||
<add-channel id="lastEventSection">
|
||||
<type>jablotron:lastEventSection</type>
|
||||
<label>Alarm Last Event Section</label>
|
||||
</add-channel>
|
||||
</instruction-set>
|
||||
</thing-type>
|
||||
|
||||
</update:update-descriptions>
|
Loading…
Reference in New Issue