[freeboxos] Complete Alarm system handling (#17233)

* Initiating the addition of the PIR sensor
* Finalized integration of the alarm system
* Corrected bug in initialization of basic-shutter

Signed-off-by: Gaël L'hopital <gael@lhopital.org>
This commit is contained in:
Gaël L'hopital 2024-08-20 18:24:37 +02:00 committed by GitHub
parent 5975a5b065
commit b00db4dd01
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 299 additions and 60 deletions

View File

@ -71,9 +71,9 @@ public class FreeboxOsBindingConstants {
public static final Set<ThingTypeUID> THINGS_TYPES_UIDS = Set.of(THING_TYPE_FXS, THING_TYPE_DECT, THING_TYPE_CALL,
THING_TYPE_HOST, THING_TYPE_VM, THING_TYPE_PLAYER, THING_TYPE_ACTIVE_PLAYER, THING_TYPE_DELTA,
THING_TYPE_REVOLUTION, THING_TYPE_REPEATER, THING_TYPE_WIFI_HOST, THING_TYPE_FREEPLUG);
public static final Set<ThingTypeUID> HOME_TYPES_UIDS = Set.of(Category.BASIC_SHUTTER.getThingTypeUID(),
Category.SHUTTER.getThingTypeUID(), Category.KFB.getThingTypeUID(), Category.CAMERA.getThingTypeUID(),
Category.ALARM.getThingTypeUID());
public static final Set<ThingTypeUID> HOME_TYPES_UIDS = Set.of(Category.BASIC_SHUTTER.thingTypeUID,
Category.SHUTTER.thingTypeUID, Category.KFB.thingTypeUID, Category.CAMERA.thingTypeUID,
Category.ALARM.thingTypeUID, Category.PIR.thingTypeUID);
protected static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Stream
.of(BRIDGE_TYPE_UIDS, THINGS_TYPES_UIDS, HOME_TYPES_UIDS).flatMap(Set::stream).collect(Collectors.toSet());
@ -175,20 +175,30 @@ public class FreeboxOsBindingConstants {
public static final String XDSL_UPTIME = "uptime";
// Home channels
public static final String TIMESTAMP_POSTFIX = "-timestamp";
public static final String KEYFOB_ENABLE = "enable";
public static final String KEYFOB_PUSHED = "pushed";
public static final String KEYFOB_PUSHED_UPDATE = KEYFOB_PUSHED + TIMESTAMP_POSTFIX;
public static final String NODE_BATTERY = "battery";
public static final String SHUTTER_POSITION = "position-set";
public static final String SHUTTER_STOP = "stop";
public static final String BASIC_SHUTTER_STATE = "state";
public static final String BASIC_SHUTTER_UP = "up";
public static final String BASIC_SHUTTER_DOWN = "down";
// public static final String BASIC_SHUTTER_CMD = "basic-shutter";
public static final String ALARM_PIN = "pin";
public static final String ALARM_SOUND = "sound";
public static final String ALARM_VOLUME = "volume";
public static final String ALARM_TIMEOUT1 = "timeout1";
public static final String ALARM_TIMEOUT2 = "timeout2";
public static final String ALARM_TIMEOUT3 = "timeout3";
public static final String ALARM_STATE = "state";
public static final String PIR_TAMPER = "tamper";
public static final String PIR_TRIGGER = "trigger";
public static final String PIR_TAMPER_UPDATE = PIR_TAMPER + TIMESTAMP_POSTFIX;
public static final String PIR_TRIGGER_UPDATE = PIR_TRIGGER + TIMESTAMP_POSTFIX;
public static final Set<Command> TRUE_COMMANDS = Set.of(OnOffType.ON, UpDownType.UP, OpenClosedType.OPEN);
public static final Set<Class<?>> ON_OFF_CLASSES = Set.of(OnOffType.class, UpDownType.class, OpenClosedType.class);

View File

@ -20,7 +20,6 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.freeboxos.internal.api.ApiHandler;
import org.openhab.binding.freeboxos.internal.api.rest.FreeboxOsSession;
import org.openhab.binding.freeboxos.internal.api.rest.HomeManager.Category;
@ -35,6 +34,7 @@ import org.openhab.binding.freeboxos.internal.handler.FreeplugHandler;
import org.openhab.binding.freeboxos.internal.handler.FxsHandler;
import org.openhab.binding.freeboxos.internal.handler.HostHandler;
import org.openhab.binding.freeboxos.internal.handler.KeyfobHandler;
import org.openhab.binding.freeboxos.internal.handler.PirHandler;
import org.openhab.binding.freeboxos.internal.handler.PlayerHandler;
import org.openhab.binding.freeboxos.internal.handler.RepeaterHandler;
import org.openhab.binding.freeboxos.internal.handler.RevolutionHandler;
@ -56,6 +56,7 @@ import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
@ -76,7 +77,6 @@ public class FreeboxOsHandlerFactory extends BaseThingHandlerFactory {
private final NetworkAddressService networkAddressService;
private final AudioHTTPServer audioHTTPServer;
private final HttpClient httpClient;
private final ApiHandler apiHandler;
private String callbackURL = "";
@ -88,13 +88,19 @@ public class FreeboxOsHandlerFactory extends BaseThingHandlerFactory {
super.activate(componentContext);
this.audioHTTPServer = audioHTTPServer;
this.httpClient = httpClientFactory.getCommonHttpClient();
this.networkAddressService = networkAddressService;
this.apiHandler = new ApiHandler(httpClient, timeZoneProvider);
this.apiHandler = new ApiHandler(httpClientFactory, timeZoneProvider);
configChanged(config);
}
@Override
@Deactivate
public void deactivate(ComponentContext componentContext) {
super.deactivate(componentContext);
apiHandler.dispose();
}
@Modified
public void configChanged(Map<String, Object> config) {
String timeout = (String) config.getOrDefault(TIMEOUT, "8");
@ -149,16 +155,18 @@ public class FreeboxOsHandlerFactory extends BaseThingHandlerFactory {
return new ActivePlayerHandler(thing);
} else if (THING_TYPE_PLAYER.equals(thingTypeUID)) {
return new PlayerHandler(thing);
} else if (Category.BASIC_SHUTTER.getThingTypeUID().equals(thingTypeUID)) {
} else if (Category.BASIC_SHUTTER.thingTypeUID.equals(thingTypeUID)) {
return new BasicShutterHandler(thing);
} else if (Category.SHUTTER.getThingTypeUID().equals(thingTypeUID)) {
} else if (Category.SHUTTER.thingTypeUID.equals(thingTypeUID)) {
return new ShutterHandler(thing);
} else if (Category.ALARM.getThingTypeUID().equals(thingTypeUID)) {
} else if (Category.ALARM.thingTypeUID.equals(thingTypeUID)) {
return new AlarmHandler(thing);
} else if (Category.KFB.getThingTypeUID().equals(thingTypeUID)) {
} else if (Category.KFB.thingTypeUID.equals(thingTypeUID)) {
return new KeyfobHandler(thing);
} else if (Category.CAMERA.getThingTypeUID().equals(thingTypeUID)) {
} else if (Category.CAMERA.thingTypeUID.equals(thingTypeUID)) {
return new CameraHandler(thing);
} else if (Category.PIR.thingTypeUID.equals(thingTypeUID)) {
return new PirHandler(thing);
}
return null;

View File

@ -32,11 +32,13 @@ import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpStatus.Code;
import org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants;
import org.openhab.binding.freeboxos.internal.api.deserialization.ForegroundAppDeserializer;
import org.openhab.binding.freeboxos.internal.api.deserialization.ListDeserializer;
import org.openhab.binding.freeboxos.internal.api.deserialization.StrictEnumTypeAdapterFactory;
import org.openhab.binding.freeboxos.internal.api.rest.PlayerManager.ForegroundApp;
import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -58,9 +60,10 @@ import inet.ipaddr.mac.MACAddress;
*/
@NonNullByDefault
public class ApiHandler {
public static final String AUTH_HEADER = "X-Fbx-App-Auth";
private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private static final String CONTENT_TYPE = "application/json; charset=" + DEFAULT_CHARSET.name();
private static final int RESPONSE_BUFFER_SIZE = 65536;
public static final String AUTH_HEADER = "X-Fbx-App-Auth";
private final Logger logger = LoggerFactory.getLogger(ApiHandler.class);
private final HttpClient httpClient;
@ -68,8 +71,7 @@ public class ApiHandler {
private long timeoutInMs = TimeUnit.SECONDS.toMillis(8);
public ApiHandler(HttpClient httpClient, TimeZoneProvider timeZoneProvider) {
this.httpClient = httpClient;
public ApiHandler(HttpClientFactory httpClientFactory, TimeZoneProvider timeZoneProvider) {
this.gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(ZonedDateTime.class,
(JsonDeserializer<ZonedDateTime>) (json, type, jsonDeserializationContext) -> {
@ -86,6 +88,21 @@ public class ApiHandler {
.registerTypeAdapter(ForegroundApp.class, new ForegroundAppDeserializer())
.registerTypeAdapter(List.class, new ListDeserializer()).serializeNulls()
.registerTypeAdapterFactory(new StrictEnumTypeAdapterFactory()).create();
httpClient = httpClientFactory.createHttpClient(FreeboxOsBindingConstants.BINDING_ID);
httpClient.setResponseBufferSize(RESPONSE_BUFFER_SIZE);
try {
httpClient.start();
} catch (Exception e) {
logger.warn("Unable to start httpClient: {}", e.getMessage());
}
}
public void dispose() {
try {
httpClient.stop();
} catch (Exception e) {
logger.warn("Unable to stop httpClient: {}", e.getMessage());
}
}
public synchronized <T> T executeUri(URI uri, HttpMethod method, Class<T> clazz, @Nullable String sessionToken,

View File

@ -14,8 +14,10 @@ package org.openhab.binding.freeboxos.internal.api.rest;
import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.BINDING_ID;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -102,17 +104,25 @@ public class HomeManager extends RestManager {
}
}
private static record LogEntry(long timestamp, int value) {
public static record LogEntry(Long timestamp, int value) {
}
public static record Endpoint(int id, String name, String label, EpType epType, Visibility visibility, int refresh,
ValueType valueType, EndpointUi ui, @Nullable String category, Object value, List<LogEntry> history) {
ValueType valueType, EndpointUi ui, @Nullable String category, Object value,
@Nullable List<LogEntry> history) {
private static final Comparator<LogEntry> HISTORY_COMPARATOR = Comparator.comparing(LogEntry::timestamp);
private enum Visibility {
INTERNAL,
NORMAL,
DASHBOARD,
UNKNOWN
}
public Optional<LogEntry> getLastChange() {
return history != null ? history.stream().max(HISTORY_COMPARATOR) : Optional.empty();
}
}
private enum Status {
@ -129,16 +139,13 @@ public class HomeManager extends RestManager {
ALARM,
KFB,
CAMERA,
PIR,
UNKNOWN;
private final ThingTypeUID thingTypeUID;
public final ThingTypeUID thingTypeUID;
Category() {
thingTypeUID = new ThingTypeUID(BINDING_ID, name().toLowerCase());
}
public ThingTypeUID getThingTypeUID() {
return thingTypeUID;
thingTypeUID = new ThingTypeUID(BINDING_ID, name().toLowerCase().replace('_', '-'));
}
}
@ -148,6 +155,17 @@ public class HomeManager extends RestManager {
public static record HomeNode(int id, @Nullable String name, @Nullable String label, Category category,
Status status, List<Endpoint> showEndpoints, Map<String, String> props, NodeType type) {
private static final Comparator<Endpoint> ENPOINT_COMPARATOR = Comparator.comparing(Endpoint::refresh);
public Optional<Endpoint> getMinRefresh() {
return showEndpoints.stream().filter(ep -> EpType.SIGNAL.equals(ep.epType) && ep.refresh() != 0)
.min(ENPOINT_COMPARATOR);
}
public Optional<Endpoint> getEndpoint(int slotId) {
return showEndpoints.stream().filter(ep -> ep.id == slotId).findAny();
}
}
public HomeManager(FreeboxOsSession session) throws FreeboxException {

View File

@ -41,7 +41,7 @@ public class NodeConfigurationBuilder {
if (node.category() == Category.UNKNOWN) {
return Optional.empty();
}
ThingUID thingUID = new ThingUID(node.category().getThingTypeUID(), bridgeUID, Integer.toString(node.id()));
ThingUID thingUID = new ThingUID(node.category().thingTypeUID, bridgeUID, Integer.toString(node.id()));
DiscoveryResultBuilder discoveryResultBuilder = DiscoveryResultBuilder.create(thingUID);
discoveryResultBuilder.withProperty(ClientConfiguration.ID, node.id()).withLabel(node.label())
.withRepresentationProperty(ClientConfiguration.ID).withBridge(bridgeUID);

View File

@ -14,8 +14,10 @@ package org.openhab.binding.freeboxos.internal.handler;
import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.*;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.freeboxos.internal.api.rest.HomeManager;
import org.openhab.binding.freeboxos.internal.api.rest.HomeManager.Endpoint;
import org.openhab.binding.freeboxos.internal.api.rest.HomeManager.EndpointState;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.QuantityType;
@ -38,7 +40,7 @@ public class AlarmHandler extends HomeNodeHandler {
}
@Override
protected State getChannelState(HomeManager homeManager, String channelId, EndpointState state) {
protected State getChannelState(String channelId, EndpointState state, Optional<Endpoint> endPoint) {
String value = state.value();
if (value == null) {
@ -47,7 +49,7 @@ public class AlarmHandler extends HomeNodeHandler {
return switch (channelId) {
case NODE_BATTERY -> DecimalType.valueOf(value);
case ALARM_PIN -> StringType.valueOf(value);
case ALARM_STATE, ALARM_PIN -> StringType.valueOf(value);
case ALARM_SOUND, ALARM_VOLUME -> QuantityType.valueOf(value + " %");
case ALARM_TIMEOUT1, ALARM_TIMEOUT2, ALARM_TIMEOUT3 -> QuantityType.valueOf(value + " s");
default -> UnDefType.NULL;

View File

@ -15,6 +15,7 @@ package org.openhab.binding.freeboxos.internal.handler;
import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.*;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -50,7 +51,7 @@ public class BasicShutterHandler extends HomeNodeHandler {
}
@Override
protected State getChannelState(HomeManager homeManager, String channelId, EndpointState state) {
protected State getChannelState(String channelId, EndpointState state, Optional<Endpoint> endPoint) {
String value = state.value();
return value != null && channelId.equals(BASIC_SHUTTER_STATE)
? state.asBoolean() ? OpenClosedType.CLOSED : OpenClosedType.OPEN

View File

@ -12,10 +12,12 @@
*/
package org.openhab.binding.freeboxos.internal.handler;
import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.TIMESTAMP_POSTFIX;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
@ -53,48 +55,52 @@ public abstract class HomeNodeHandler extends ApiConsumerHandler {
HomeNode node = getManager(HomeManager.class).getHomeNode(getClientId());
// Gets the lowest refresh time or else, we'll keep configuration default
node.showEndpoints().stream().filter(ep -> ep.epType() == EpType.SIGNAL).filter(ep -> ep.refresh() != 0)
.min(Comparator.comparing(Endpoint::refresh)).map(Endpoint::refresh).ifPresent(rate -> {
Configuration thingConfig = editConfiguration();
thingConfig.put(ApiConsumerConfiguration.REFRESH_INTERVAL, Integer.toString(rate / 1000));
updateConfiguration(thingConfig);
});
node.getMinRefresh().map(Endpoint::refresh).ifPresent(rate -> {
Configuration thingConfig = editConfiguration();
thingConfig.put(ApiConsumerConfiguration.REFRESH_INTERVAL, Integer.toString(rate / 1000));
updateConfiguration(thingConfig);
});
properties.putAll(node.props());
getThing().getChannels().forEach(channel -> {
Configuration conf = channel.getConfiguration();
node.type().endpoints().stream().filter(ep -> ep.name().equals(channel.getUID().getIdWithoutGroup()))
String channelId = channel.getUID().getIdWithoutGroup();
node.type().endpoints().stream().filter(ep -> ep.name().equals(channelId))
.forEach(endPoint -> conf.put(endPoint.epType().asConfId(), endPoint.id()));
internalConfigureChannel(channel.getUID().getIdWithoutGroup(), conf, node.type().endpoints());
internalConfigureChannel(channelId, conf, node.type().endpoints());
});
}
protected void internalConfigureChannel(String channelId, Configuration conf, List<Endpoint> endpoints) {
if (channelId.endsWith(TIMESTAMP_POSTFIX)) {
String baseEndpoint = channelId.replace(TIMESTAMP_POSTFIX, "");
endpoints.stream().filter(ep -> ep.name().equals(baseEndpoint)).forEach(ep -> {
conf.put(ep.name(), ep.id());
conf.put("signal", ep.id());
});
}
}
@Override
protected void internalPoll() throws FreeboxException {
HomeManager homeManager = getManager(HomeManager.class);
getThing().getChannels().stream().filter(channel -> isLinked(channel.getUID())).forEach(channel -> {
State result = UnDefType.UNDEF;
HomeNode node = homeManager.getHomeNode(getClientId());
List<Channel> linkedChannels = getThing().getChannels().stream().filter(channel -> isLinked(channel.getUID()))
.toList();
for (Channel channel : linkedChannels) {
State result = null;
Integer slotId = getSlotId(channel.getConfiguration(), EpType.SIGNAL.asConfId());
if (slotId instanceof Integer) {
try {
EndpointState state = homeManager.getEndpointsState(getClientId(), slotId);
if (state != null) {
result = getChannelState(homeManager, channel.getUID().getIdWithoutGroup(), state);
} else {
result = getChannelState(homeManager, channel.getUID().getIdWithoutGroup());
}
} catch (FreeboxException e) {
logger.warn("Error updating channel: {}", e.getMessage());
EndpointState state = homeManager.getEndpointsState(getClientId(), slotId);
Optional<Endpoint> endPoint = node.getEndpoint(slotId);
if (state != null) {
result = getChannelState(channel.getUID().getIdWithoutGroup(), state, endPoint);
}
} else {
result = getChannelState(homeManager, channel.getUID().getIdWithoutGroup());
}
updateState(channel.getUID(), result);
});
updateState(channel.getUID(), result != null ? result : UnDefType.UNDEF);
}
}
@Override
@ -126,9 +132,5 @@ public abstract class HomeNodeHandler extends ApiConsumerHandler {
return false;
}
protected State getChannelState(HomeManager homeManager, String channelWG) {
return UnDefType.UNDEF;
}
protected abstract State getChannelState(HomeManager homeManager, String channelId, EndpointState state);
protected abstract State getChannelState(String channelId, EndpointState state, Optional<Endpoint> endPoint);
}

View File

@ -14,11 +14,19 @@ package org.openhab.binding.freeboxos.internal.handler;
import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.*;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Objects;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.freeboxos.internal.api.FreeboxException;
import org.openhab.binding.freeboxos.internal.api.rest.HomeManager;
import org.openhab.binding.freeboxos.internal.api.rest.HomeManager.Endpoint;
import org.openhab.binding.freeboxos.internal.api.rest.HomeManager.EndpointState;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Thing;
@ -40,7 +48,15 @@ public class KeyfobHandler extends HomeNodeHandler {
}
@Override
protected State getChannelState(HomeManager homeManager, String channelId, EndpointState state) {
protected State getChannelState(String channelId, EndpointState state, Optional<Endpoint> endPoint) {
if (channelId.startsWith(KEYFOB_PUSHED)) {
return Objects.requireNonNull(endPoint.map(ep -> ep
.getLastChange().map(
change -> (State) (KEYFOB_PUSHED.equals(channelId) ? new DecimalType(change.value())
: new DateTimeType(ZonedDateTime
.ofInstant(Instant.ofEpochSecond(change.timestamp()), ZoneOffset.UTC))))
.orElse(UnDefType.UNDEF)).orElse(UnDefType.UNDEF));
}
String value = state.value();
if (value != null) {
switch (channelId) {

View File

@ -0,0 +1,69 @@
/**
* Copyright (c) 2010-2024 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.freeboxos.internal.handler;
import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.*;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Objects;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.freeboxos.internal.api.rest.HomeManager.Endpoint;
import org.openhab.binding.freeboxos.internal.api.rest.HomeManager.EndpointState;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
/**
* The {@link PirHandler} is responsible for handling everything associated to
* any Freebox Home PIR motion detection thing type.
*
* @author Gaël L'hopital - Initial contribution
*/
@NonNullByDefault
public class PirHandler extends HomeNodeHandler {
public PirHandler(Thing thing) {
super(thing);
}
@Override
protected State getChannelState(String channelId, EndpointState state, Optional<Endpoint> endPoint) {
if (PIR_TAMPER_UPDATE.equals(channelId) || PIR_TRIGGER_UPDATE.equals(channelId)) {
return Objects.requireNonNull(endPoint.map(ep -> ep.getLastChange()
.map(change -> (State) new DateTimeType(
ZonedDateTime.ofInstant(Instant.ofEpochSecond(change.timestamp()), ZoneOffset.UTC)))
.orElse(UnDefType.UNDEF)).orElse(UnDefType.UNDEF));
}
String value = state.value();
if (value == null) {
return UnDefType.NULL;
}
return switch (channelId) {
case NODE_BATTERY -> DecimalType.valueOf(value);
case PIR_TAMPER -> state.asBoolean() ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
case PIR_TRIGGER -> OnOffType.from(value);
default -> UnDefType.NULL;
};
}
}

View File

@ -15,6 +15,7 @@ package org.openhab.binding.freeboxos.internal.handler;
import static org.openhab.binding.freeboxos.internal.FreeboxOsBindingConstants.*;
import java.util.List;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.freeboxos.internal.api.FreeboxException;
@ -49,7 +50,7 @@ public class ShutterHandler extends HomeNodeHandler {
}
@Override
protected State getChannelState(HomeManager homeManager, String channelId, EndpointState state) {
protected State getChannelState(String channelId, EndpointState state, Optional<Endpoint> endPoint) {
String value = state.value();
return value != null && channelId.equals(SHUTTER_POSITION) ? QuantityType.valueOf(value + " %")
: UnDefType.NULL;

View File

@ -46,6 +46,14 @@ thing-type.freeboxos.host.label = Network Device
thing-type.freeboxos.host.description = Provides network device reachability
thing-type.freeboxos.kfb.label = Freebox Keyfob
thing-type.freeboxos.kfb.description = A keyfob configured in your Freebox Server
thing-type.freeboxos.kfb.channel.pushed-timestamp.label = Timestamp
thing-type.freeboxos.kfb.channel.pushed-timestamp.description = Timestamp of the last action on the keyfob
thing-type.freeboxos.pir.label = Freebox Home PIR
thing-type.freeboxos.pir.description = A motion Sensor
thing-type.freeboxos.pir.channel.tamper-timestamp.label = Tamper Timestamp
thing-type.freeboxos.pir.channel.tamper-timestamp.description = Timestamp of the last cover tampered state change
thing-type.freeboxos.pir.channel.trigger-timestamp.label = Trigger Timestamp
thing-type.freeboxos.pir.channel.trigger-timestamp.description = Timestamp of the last state change
thing-type.freeboxos.player.label = Freebox Player
thing-type.freeboxos.player.description = The player is the device connected to your TV
thing-type.freeboxos.repeater.label = Wifi Repeater
@ -209,6 +217,13 @@ channel-type.freeboxos.afp-file-status.description = Status of Mac OS File Shari
channel-type.freeboxos.airmedia-status.label = Air Media Enabled
channel-type.freeboxos.airmedia-status.description = Indicates whether Air Media is enabled
channel-type.freeboxos.alarm-pin.label = PIN Code
channel-type.freeboxos.alarm-state.label = Alarm State
channel-type.freeboxos.alarm-state.description = Current state of the alarm system
channel-type.freeboxos.alarm-state.state.option.idle = Idle
channel-type.freeboxos.alarm-state.state.option.alarm1_arming = Arming (Absent Mode)
channel-type.freeboxos.alarm-state.state.option.alarm1_armed = Armed (Absent Mode)
channel-type.freeboxos.alarm-state.state.option.alarm2_arming = Arming (Night Mode)
channel-type.freeboxos.alarm-state.state.option.alarm2_armed = Armed (Night Mode)
channel-type.freeboxos.alarm-timeout.label = Alarm Duration
channel-type.freeboxos.alarm-volume.label = Alarm Volume
channel-type.freeboxos.alternate-ring.label = Alternating Ring
@ -282,6 +297,11 @@ channel-type.freeboxos.key-code.state.option.ok = OK
channel-type.freeboxos.key-code.state.option.home = Home
channel-type.freeboxos.keyfob-enable.label = Keyfob Enabled
channel-type.freeboxos.keyfob-enable.description = Activates / deactivates the keyfob
channel-type.freeboxos.kfb-pushed.label = Key Code Pushed
channel-type.freeboxos.kfb-pushed.description = Last key pushed on the remote
channel-type.freeboxos.kfb-pushed.state.option.1 = Arm Absent Mode
channel-type.freeboxos.kfb-pushed.state.option.2 = Disarm
channel-type.freeboxos.kfb-pushed.state.option.3 = Arm Night Mode
channel-type.freeboxos.lcd-brightness.label = Screen Brightness
channel-type.freeboxos.lcd-brightness.description = Brightness level of the screen in percent
channel-type.freeboxos.lcd-forced.label = Forced Orientation
@ -323,6 +343,8 @@ channel-type.freeboxos.package.description = Name of the package currently activ
channel-type.freeboxos.phone-event.label = Phone Event
channel-type.freeboxos.phone-event.description = Triggers when an event related to the phone has been detected
channel-type.freeboxos.phone-number.label = Phone Number
channel-type.freeboxos.pir-tamper.label = Cover Tamper
channel-type.freeboxos.pir-trigger.label = Détection
channel-type.freeboxos.player-status.label = Player Status
channel-type.freeboxos.player-status.description = Status of the Freebox TV player
channel-type.freeboxos.reachable.label = Reachable

View File

@ -496,6 +496,46 @@
<state readOnly="true" pattern="%.2f dBm"/>
</channel-type>
<channel-type id="pir-trigger">
<item-type>Switch</item-type>
<label>Détection</label>
<category>oh:freeboxos:mouvement</category>
</channel-type>
<channel-type id="pir-tamper">
<item-type>Contact</item-type>
<label>Cover Tamper</label>
<category>oh:freeboxos:warning</category>
</channel-type>
<channel-type id="kfb-pushed">
<item-type>Number</item-type>
<label>Key Code Pushed</label>
<description>Last key pushed on the remote</description>
<state readOnly="true" pattern="%d">
<options>
<option value="1">Arm Absent Mode</option>
<option value="2">Disarm</option>
<option value="3">Arm Night Mode</option>
</options>
</state>
</channel-type>
<channel-type id="alarm-state">
<item-type>String</item-type>
<label>Alarm State</label>
<description>Current state of the alarm system</description>
<state readOnly="true" pattern="%s">
<options>
<option value="idle">Idle</option>
<option value="alarm1_arming">Arming (Absent Mode)</option>
<option value="alarm1_armed">Armed (Absent Mode)</option>
<option value="alarm2_arming">Arming (Night Mode)</option>
<option value="alarm2_armed">Armed (Night Mode)</option>
</options>
</state>
</channel-type>
<channel-type id="xdsl-ready">
<item-type>Switch</item-type>
<label>Ready</label>

View File

@ -21,6 +21,33 @@
<config-description-ref uri="thing-type:freeboxos:home-node"/>
</thing-type>
<thing-type id="pir">
<supported-bridge-type-refs>
<bridge-type-ref id="api"/>
</supported-bridge-type-refs>
<label>Freebox Home PIR</label>
<description>A motion Sensor</description>
<channels>
<channel id="trigger" typeId="pir-trigger"/>
<channel id="trigger-timestamp" typeId="timestamp">
<label>Trigger Timestamp</label>
<description>Timestamp of the last state change</description>
</channel>
<channel id="tamper" typeId="pir-tamper"/>
<channel id="tamper-timestamp" typeId="timestamp">
<label>Tamper Timestamp</label>
<description>Timestamp of the last cover tampered state change</description>
</channel>
<channel id="battery" typeId="system.battery-level"/>
</channels>
<representation-property>id</representation-property>
<config-description-ref uri="thing-type:freeboxos:home-node"/>
</thing-type>
<thing-type id="alarm">
<supported-bridge-type-refs>
<bridge-type-ref id="api"/>
@ -30,6 +57,7 @@
<description>The Alarm system configured in your Freebox Server</description>
<channels>
<channel id="state" typeId="alarm-state"/>
<channel id="pin" typeId="alarm-pin"/>
<channel id="sound" typeId="alarm-volume">
<label>Bips Volume</label>
@ -64,6 +92,11 @@
<description>A keyfob configured in your Freebox Server</description>
<channels>
<channel id="pushed" typeId="kfb-pushed"/>
<channel id="pushed-timestamp" typeId="timestamp">
<label>Timestamp</label>
<description>Timestamp of the last action on the keyfob</description>
</channel>
<channel id="enable" typeId="keyfob-enable"/>
<channel id="battery" typeId="system.battery-level"/>
</channels>