[freeathome] Add Wireless Blind Actuator support, Improve connection handling (#18631)

* [freeathome] Enhancement: Added support for Wireless Blind Actuator devices

Signed-off-by: Martin Littkovsky <2018turtle@proton.me>
pull/18635/head
ML19821 2025-05-11 15:02:43 +02:00 committed by GitHub
parent a903727f69
commit 5389567089
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 634 additions and 209 deletions

View File

@ -28,4 +28,5 @@ public class FreeAtHomeBridgeHandlerConfiguration {
public String ipAddress = "";
public String username = "";
public String password = "";
public boolean sendKeepAliveMessage = false;
}

View File

@ -84,7 +84,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -97,12 +97,12 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 17, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -116,7 +116,7 @@ public class FreeAtHomeDeviceChannel {
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 256, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 1, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -129,23 +129,23 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 6, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 7, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1027, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT_AS_OUTPUT, 256, channelId,
channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -161,40 +161,40 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 304, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 333, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 331, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 54, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 51, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 320, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 68, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 58, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 56, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 66, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
// Additional channel for RTC device
if (Integer.parseInt(channelFunctionID, 16) == FID_ROOM_TEMPERATURE_CONTROLLER_MASTER_WITHOUT_FAN) {
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 48, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
}
break;
@ -208,12 +208,12 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
// 53 AL_WINDOW_DOOR Window/Door Open = 1 / closed = 0
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 53, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
// 41 AL_WINDOW_DOOR_POSITION Window/Door position Delivers position for Window/Door(Open/Tilted/Closed)
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 41, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -225,7 +225,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 4, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -238,7 +238,7 @@ public class FreeAtHomeDeviceChannel {
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 61698, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 61697, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -251,7 +251,7 @@ public class FreeAtHomeDeviceChannel {
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 256, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 2, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -264,7 +264,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 2, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -277,7 +277,7 @@ public class FreeAtHomeDeviceChannel {
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 256, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 2, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -291,19 +291,46 @@ public class FreeAtHomeDeviceChannel {
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 272, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 17, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 256, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 1, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
case FID_DIMMING_SENSOR_PUSHBUTTON_TYPE0:
case FID_DIMMING_SENSOR_PUSHBUTTON_TYPE1:
case FID_DIMMING_SENSOR_PUSHBUTTON_TYPE2:
case FID_DIMMING_SENSOR_PUSHBUTTON_TYPE3:
case FID_DIMMING_SENSOR_PUSHBUTTON_TYPE4:
case FID_DIMMING_SENSOR_PUSHBUTTON_TYPE5:
case FID_DIMMING_SENSOR_PUSHBUTTON_TYPE6:
case FID_DIMMING_SENSOR_PUSHBUTTON_TYPE7: {
this.channelId = channelId;
logger.debug("Dimming actuator channel - Channel FID: 0x{}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 17, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 272, channelId, channelObject);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 256, channelId, channelObject);
addDatapointGroup(newDatapointGroup);
break;
}
case FID_AWNING_ACTUATOR:
case FID_ATTIC_WINDOW_ACTUATOR:
case FID_BLIND_ACTUATOR:
case FID_BLIND_ACTUATOR_WIRELESS:
case FID_SHUTTER_ACTUATOR: {
this.channelId = channelId;
@ -312,17 +339,17 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 32, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 288, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 33, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 288, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 289, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 35, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
/*
* 290 AL_CURRENT_ABSOLUTE_POSITION_SLATS_PERCENTAGE Current Absolute Position Slats Percentage Indicate
@ -333,7 +360,14 @@ public class FreeAtHomeDeviceChannel {
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 290, channelId, channelObject);
newDatapointGroup.addDatapointToGroup(DatapointDirection.INPUT, 36, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
case FID_BLIND_SENSOR: {
this.channelId = channelId;
logger.warn("Blind sensor channel - Channel FID: 0x{}, not implemented yet", channelFunctionID);
break;
}
@ -344,11 +378,11 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1026, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1027, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -359,15 +393,15 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 39, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1029, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1030, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -378,17 +412,17 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
if (newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 38, channelId, channelObject)) {
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
}
newDatapointGroup = new FreeAtHomeDatapointGroup();
if (newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1024, channelId, channelObject)) {
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
}
newDatapointGroup = new FreeAtHomeDatapointGroup();
if (newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 304, channelId, channelObject)) {
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
}
break;
@ -400,15 +434,15 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 37, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1025, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1028, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -419,7 +453,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1564, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -430,7 +464,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1563, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -441,7 +475,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 337, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -452,7 +486,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1562, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -463,7 +497,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1565, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -474,7 +508,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1566, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -485,7 +519,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1567, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -496,7 +530,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1569, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -507,7 +541,7 @@ public class FreeAtHomeDeviceChannel {
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 1568, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
@ -516,19 +550,18 @@ public class FreeAtHomeDeviceChannel {
logger.debug("Wind Alarm channel - Channel FID: 0x{}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 37, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
case FID_RAIN_ALARM_SENSOR: { // 0x000E Wind Alarm
case FID_RAIN_ALARM_SENSOR: { // 0x000E Rain Alarm
this.channelId = channelId;
logger.debug("Rain Alarm channel - Channel FID: 0x{}", channelFunctionID);
FreeAtHomeDatapointGroup newDatapointGroup = new FreeAtHomeDatapointGroup();
newDatapointGroup.addDatapointToGroup(DatapointDirection.OUTPUT, 39, channelId, channelObject);
AddDatapointGroup(newDatapointGroup);
addDatapointGroup(newDatapointGroup);
break;
}
case FID_SCENE_SENSOR: {
this.channelId = channelId;
@ -537,7 +570,6 @@ public class FreeAtHomeDeviceChannel {
break;
}
default: {
logger.debug("Unknown channel found - Channel FID: 0x{}", channelFunctionID);
@ -584,7 +616,7 @@ public class FreeAtHomeDeviceChannel {
}
}
private void AddDatapointGroup(FreeAtHomeDatapointGroup DatapointGroup) {
private void addDatapointGroup(FreeAtHomeDatapointGroup DatapointGroup) {
if (DatapointGroup.isValid()) {
logger.debug("Datapoint group is added");
datapointGroups.add(DatapointGroup);

View File

@ -16,6 +16,7 @@ import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collection;
@ -83,33 +84,37 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeBridgeHandler.class);
private Map<String, FreeAtHomeDeviceHandler> mapEventListeners = new ConcurrentHashMap<>();
private final Map<String, FreeAtHomeDeviceHandler> mapEventListeners = new ConcurrentHashMap<>();
// Clients for the network communication
private HttpClient httpClient;
private final HttpClient httpClient;
private @Nullable WebSocketClient websocketClient = null;
private FreeAtHomeWebsocketMonitorThread socketMonitor = new FreeAtHomeWebsocketMonitorThread();
private final FreeAtHomeWebsocketMonitorThread socketMonitor = new FreeAtHomeWebsocketMonitorThread();
private @Nullable QueuedThreadPool jettyThreadPool = null;
private volatile @Nullable Session websocketSession = null;
private String sysApUID = "00000000-0000-0000-0000-000000000000";
private final String sysApUID = "00000000-0000-0000-0000-000000000000";
private String ipAddress = "";
private String username = "";
private String password = "";
private boolean sendKeepAliveMessage = true;
private String baseUrl = "";
private String authField = "";
private Lock lock = new ReentrantLock();
private AtomicBoolean httpConnectionOK = new AtomicBoolean(false);
private Condition websocketSessionEstablished = lock.newCondition();
private String sysapVersion = "";
private final Lock lock = new ReentrantLock();
private final AtomicBoolean httpConnectionOK = new AtomicBoolean(false);
private final Condition websocketSessionEstablished = lock.newCondition();
private volatile long lastReceivedTime = 0;
int numberOfComponents = 0;
private static final int BRIDGE_WEBSOCKET_RECONNECT_DELAY = 60;
private static final int BRIDGE_WEBSOCKET_TIMEOUT = 90;
private static final int BRIDGE_WEBSOCKET_KEEPALIVE = 50;
private static final int BRIDGE_WEBSOCKET_RECONNECT_DELAY = 5; // Seconds
private static final int BRIDGE_WEBSOCKET_TIMEOUT = 90; // Seconds
private static final int BRIDGE_WEBSOCKET_KEEPALIVE = 10; // Seconds
private static final String BRIDGE_URL_GETDEVICELIST = "/rest/devicelist";
public FreeAtHomeBridgeHandler(Bridge thing, HttpClient client) {
@ -131,10 +136,85 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
return List.of(FreeAtHomeDiscoveryService.class);
}
/**
* Method to fetch SysApp Version
*/
public boolean fetchSysapVersion() {
String url = baseUrl + "/rest/configuration";
try {
HttpClient client = httpClient;
Request req = client.newRequest(url);
if (req == null) {
logger.warn("Invalid request object in fetchSysapVersion with the URL [ {} ]", url);
return false;
}
ContentResponse response = req.send();
if (response.getStatus() != 200) {
logger.warn("HTTP request failed in fetchSysapVersion with status [{}] and reason [{}]",
response.getStatus(), response.getReason());
return false;
}
String configString = new String(response.getContent());
JsonReader reader = new JsonReader(new StringReader(configString));
reader.setLenient(true); // Deprecated: use reader.setStrictness(Strictness.LENIENT) in future. Kept for
// backward compatibility with older library versions.
JsonElement jsonTree = JsonParser.parseReader(reader);
if (!jsonTree.isJsonObject()) {
logger.warn("Invalid jsonObject in fetchSysapVersion with the URL [ {} ]", url);
return false;
}
JsonObject jsonObject = jsonTree.getAsJsonObject();
JsonObject sysapObject = jsonObject.getAsJsonObject(sysApUID);
if (sysapObject == null) {
logger.warn("SysAP object not found in fetchSysapVersion with the URL [ {} ]", url);
return false;
}
JsonObject sysapDetails = sysapObject.getAsJsonObject("sysap");
if (sysapDetails == null) {
logger.warn("SysAP details not found in fetchSysapVersion with the URL [ {} ]", url);
return false;
}
JsonElement versionElement = sysapDetails.get("version");
if (versionElement == null || !versionElement.isJsonPrimitive()) {
logger.warn("Version not found or invalid in fetchSysapVersion with the URL [ {} ]", url);
return false;
}
sysapVersion = versionElement.getAsString();
logger.debug("SysAP version fetched: {}", sysapVersion);
return true;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.warn("Http communication interrupted in fetchSysapVersion: {}", e.getMessage());
return false;
} catch (ExecutionException | TimeoutException e) {
logger.warn("Http communication exception in fetchSysapVersion: {}", e.getMessage());
return false;
} catch (JsonParseException e) {
logger.warn("Invalid JSON in fetchSysapVersion: {}", e.getMessage());
return false;
} catch (Exception e) {
logger.warn("Unexpected error in fetchSysapVersion: {}", e.getMessage());
return false;
}
}
/**
* Method to get the device list
*/
public List<String> getDeviceDeviceList() throws FreeAtHomeHttpCommunicationException {
fetchSysapVersion();
List<String> listOfComponentId = new ArrayList<String>();
boolean ret = false;
@ -232,7 +312,8 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
String deviceString = new String(response.getContent());
JsonReader reader = new JsonReader(new StringReader(deviceString));
reader.setLenient(true);
reader.setLenient(true); // Deprecated: use reader.setStrictness(Strictness.LENIENT) in future. Kept for
// backward compatibility with older library versions.
JsonElement jsonTree = JsonParser.parseReader(reader);
if (!jsonTree.isJsonObject()) {
@ -312,7 +393,8 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
String deviceString = new String(response.getContent());
JsonReader reader = new JsonReader(new StringReader(deviceString));
reader.setLenient(true);
reader.setLenient(true); // Deprecated: use reader.setStrictness(Strictness.LENIENT) in future. Kept for
// backward compatibility with older library versions.
JsonElement jsonTree = JsonParser.parseReader(reader);
if (!jsonTree.isJsonObject()) {
@ -403,7 +485,8 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
*/
public void setDatapointOnWebsocketFeedback(String receivedText) {
JsonReader reader = new JsonReader(new StringReader(receivedText));
reader.setLenient(true);
reader.setLenient(true); // Deprecated: use reader.setStrictness(Strictness.LENIENT) in future. Kept for
// backward compatibility with older library versions.
JsonElement jsonTree = JsonParser.parseReader(reader);
// check the output
@ -439,7 +522,8 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
public void markDeviceRemovedOnWebsocketFeedback(String receivedText) {
JsonReader reader = new JsonReader(new StringReader(receivedText));
reader.setLenient(true);
reader.setLenient(true); // Deprecated: use reader.setStrictness(Strictness.LENIENT) in future. Kept for
// backward compatibility with older library versions.
JsonElement jsonTree = JsonParser.parseReader(reader);
// check the output
@ -470,80 +554,114 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
}
/**
* Method to open Http connection
* Establishes an HTTP connection to the free@home system.
* This method sets up authentication and tests the connection by making a request.
*
* @return true if the HTTP connection is successfully established, false otherwise.
*/
public boolean openHttpConnection() {
boolean ret = false;
logger.debug("Attempting to open HTTP connection to free@home system");
try {
// Add authentication credentials.
// Set up authentication for the HTTP client
AuthenticationStore auth = httpClient.getAuthenticationStore();
URI baseUri = new URI(baseUrl);
auth.addAuthenticationResult(new BasicAuthentication.BasicResult(baseUri, username, password));
URI uri1 = new URI(baseUrl);
auth.addAuthenticationResult(new BasicAuthentication.BasicResult(uri1, username, password));
// Construct the URL for the device list (used as a test endpoint)
String testUrl = baseUrl + BRIDGE_URL_GETDEVICELIST;
logger.debug("Test URL for HTTP connection: {}", testUrl);
String url = baseUrl + BRIDGE_URL_GETDEVICELIST;
Request req = httpClient.newRequest(url);
ContentResponse res = req.send();
// check status
if (res.getStatus() == HttpStatus.OK_200) {
// response OK
httpConnectionOK.set(true);
ret = true;
logger.debug("HTTP connection to SysAP is OK");
} else {
// response NOK, set error
httpConnectionOK.set(false);
ret = false;
// Create and send a test request
Request request = httpClient.newRequest(testUrl);
if (request == null) {
throw new IllegalStateException("Failed to create HTTP request");
}
} catch (URISyntaxException | InterruptedException | ExecutionException | TimeoutException ex) {
logger.debug("Initial HTTP connection to SysAP is not successful");
ret = false;
// Send the request and get the response
ContentResponse response = request.send();
// Check the response status
int statusCode = response.getStatus();
if (statusCode == HttpStatus.OK_200) {
logger.debug("HTTP connection to free@home system established successfullystatus code: {}", statusCode);
httpConnectionOK.set(true);
return true;
} else {
logger.warn("HTTP connection failed. Status code: {}, Reason: {}", statusCode, response.getReason());
httpConnectionOK.set(false);
return false;
}
} catch (URISyntaxException e) {
logger.warn("Invalid URI syntax for base URL: {}", baseUrl, e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.warn("HTTP connection attempt was interrupted", e);
} catch (TimeoutException e) {
logger.warn("HTTP connection attempt timed out", e);
} catch (ExecutionException e) {
logger.warn("Error executing HTTP request", e);
} catch (Exception e) {
logger.warn("Unexpected error while opening HTTP connection", e);
}
return ret;
httpConnectionOK.set(false);
return false;
}
/**
* Method to connect the websocket session
* Method to connect the WebSocket session.
* Attempts to establish a WebSocket connection to the SysAP and handles authentication.
*
* @return true if the connection attempt is initiated successfully, false otherwise
*/
public boolean connectWebsocketSession() {
boolean ret = false;
// Create the WebSocket URI using the configured IP address
URI uri = URI.create("ws://" + ipAddress + "/fhapi/v1/api/ws");
// Combine username and password for authentication
String authString = username + ":" + password;
// create base64 encoder
// Create a Base64 encoder
Base64.Encoder bas64Encoder = Base64.getEncoder();
// Encoding string using encoder object
// Encode the authentication string to Base64
String authStringEnc = bas64Encoder.encodeToString(authString.getBytes());
// Set the Authorization header value
authField = "Basic " + authStringEnc;
WebSocketClient localWebsocketClient = websocketClient;
try {
// Start socket client
// Start the WebSocket client if it exists
if (localWebsocketClient != null) {
localWebsocketClient.setMaxTextMessageBufferSize(8 * 1024);
localWebsocketClient.setMaxIdleTimeout(BRIDGE_WEBSOCKET_TIMEOUT * 60 * 1000);
localWebsocketClient.setConnectTimeout(BRIDGE_WEBSOCKET_TIMEOUT * 60 * 1000);
// Set the maximum idle timeout for the WebSocket connection.
// If no activity occurs within this time, the connection will be closed automatically.
localWebsocketClient.setMaxIdleTimeout(BRIDGE_WEBSOCKET_TIMEOUT * 1000); // milliseconds
// Set the connection timeout for the WebSocket client.
// This defines how long the client should wait before considering the connection attempt as failed.
// Like the idle timeout, the value is converted from seconds to milliseconds.
localWebsocketClient.setConnectTimeout(BRIDGE_WEBSOCKET_TIMEOUT * 1000); // milliseconds
localWebsocketClient.start();
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setHeader("Authorization", authField);
request.setTimeout(BRIDGE_WEBSOCKET_TIMEOUT, TimeUnit.MINUTES);
// Set the timeout for the WebSocket upgrade process (i.e., the time allowed for the handshake to
// complete).
// Unlike `setConnectTimeout()`, which applies to the lower-level network connection, this timeout
// applies specifically to the WebSocket upgrade request.
// The timeout is specified in SECONDS, using `TimeUnit.SECONDS`.
request.setTimeout(BRIDGE_WEBSOCKET_TIMEOUT, TimeUnit.SECONDS);
localWebsocketClient.connect(this, uri, request);
logger.debug("Websocket connection to SysAP is OK, timeout: {}", BRIDGE_WEBSOCKET_TIMEOUT);
logger.debug("WebSocket connection attempt initiated, timeout: {} seconds", BRIDGE_WEBSOCKET_TIMEOUT);
ret = true;
} else {
ret = false;
@ -599,45 +717,67 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
}
/**
* Method to open the websocket connection
* Opens a WebSocket connection to the free@home system.
* This method initializes the thread pool and WebSocket client if they don't exist.
*
* @return true if the WebSocket connection is successfully opened or already exists, false otherwise.
*/
public boolean openWebSocketConnection() {
boolean ret = false;
QueuedThreadPool localThreadPool = jettyThreadPool;
try {
logger.debug("Current Jetty version: {}", org.eclipse.jetty.util.Jetty.VERSION);
if (localThreadPool == null) {
jettyThreadPool = new QueuedThreadPool();
QueuedThreadPool localThreadPool = jettyThreadPool;
localThreadPool = jettyThreadPool;
if (localThreadPool == null) {
// Create a new thread pool if it doesn't exist
jettyThreadPool = new QueuedThreadPool();
localThreadPool = jettyThreadPool;
if (localThreadPool != null) {
localThreadPool.setName(FreeAtHomeBridgeHandler.class.getSimpleName());
localThreadPool.setDaemon(true);
localThreadPool.setStopTimeout(0);
ret = true;
if (localThreadPool != null) {
localThreadPool.setName(FreeAtHomeBridgeHandler.class.getSimpleName());
localThreadPool.setDaemon(true);
localThreadPool.setStopTimeout(0);
} else {
throw new IllegalStateException("Failed to create QueuedThreadPool");
}
}
}
WebSocketClient localWebSocketClient = websocketClient;
WebSocketClient localWebSocketClient = websocketClient;
if (localWebSocketClient == null) {
websocketClient = new WebSocketClient(httpClient);
if (localWebSocketClient == null) {
// Create a new WebSocket client if it doesn't exist
logger.debug("Creating new WebSocketClient with Jetty version {}",
org.eclipse.jetty.util.Jetty.VERSION);
localWebSocketClient = new WebSocketClient(httpClient);
websocketClient = localWebSocketClient;
localWebSocketClient = websocketClient;
if (localWebSocketClient != null) {
localWebSocketClient.setExecutor(jettyThreadPool);
socketMonitor.start();
ret = true;
if (localWebSocketClient != null) {
// Set the executor immediately after creation, before any start
localWebSocketClient.setExecutor(localThreadPool);
// Do not start the client here; let connectWebsocketSession() handle it, see
// localWebsocketClient.start() there
socketMonitor.start();
ret = true;
} else {
throw new IllegalStateException("WebSocketClient initialization failed");
}
} else {
ret = false;
if (localWebSocketClient.isStarted()) {
logger.debug("WebSocketClient is already started, skipping setExecutor()");
ret = true; // Client exists and is running, no need to reconfigure
} else {
// Set executor only if the client is not yet started
logger.debug("WebSocketClient exists but not started, setting executor");
localWebSocketClient.setExecutor(localThreadPool);
socketMonitor.start();
ret = true;
}
}
} else {
ret = true;
} catch (Exception e) {
logger.warn("Error in openWebSocketConnection: {}", e.getMessage());
ret = false;
}
return ret;
@ -653,6 +793,8 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
// load configuration
FreeAtHomeBridgeHandlerConfiguration locConfig = getConfigAs(FreeAtHomeBridgeHandlerConfiguration.class);
sendKeepAliveMessage = locConfig.sendKeepAliveMessage;
ipAddress = locConfig.ipAddress;
if (ipAddress.isBlank()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
@ -707,63 +849,133 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
/**
* Method to dispose
*/
@SuppressWarnings("null")
@Override
public void dispose() {
// let run out the thread
logger.debug("Dispose called, interrupting socket monitor thread");
socketMonitor.interrupt();
logger.debug("Closing WebSocket connection");
closeWebSocketConnection();
if (jettyThreadPool != null) {
try {
logger.debug("Stopping Jetty thread pool");
jettyThreadPool.stop();
} catch (Exception e) {
logger.warn("Error stopping Jetty thread pool: {}", e.getMessage());
} finally {
jettyThreadPool = null;
}
}
}
/**
* Thread that maintains connection via Websocket.
* Inner class implementing the WebSocket monitor thread.
* This thread continuously monitors the WebSocket connection and attempts to reconnect if it fails.
*/
private class FreeAtHomeWebsocketMonitorThread extends Thread {
// initial delay to initiate connection
private AtomicInteger reconnectDelay = new AtomicInteger();
// AtomicInteger to manage the delay (in seconds) before attempting to reconnect the WebSocket.
// This ensures thread-safe updates to the reconnect delay value across multiple threads.
private final AtomicInteger reconnectDelay = new AtomicInteger();
/**
* Default constructor for the FreeAtHomeWebsocketMonitorThread.
* Initializes a new instance of the monitor thread without any specific configuration.
* The reconnectDelay is implicitly initialized to 0 by AtomicInteger's default constructor.
*/
public FreeAtHomeWebsocketMonitorThread() {
// No additional initialization required at this point.
// The reconnectDelay is already set to 0 by default via AtomicInteger.
}
/**
* Main execution method of the monitor thread.
* Runs a loop that checks the HTTP connection status and manages WebSocket reconnection attempts.
*/
@Override
public void run() {
// set initial connect delay to 0
// Initialize reconnect delay to 0
reconnectDelay.set(0);
int reconnectCounter = 0; // Counter for reconnection attempts
try {
while (!isInterrupted()) {
while (!isInterrupted()) {
try {
if (httpConnectionOK.get()) {
reconnectCounter++;
logger.debug("httpConnectionOK: {}", httpConnectionOK.get());
logger.debug("Attempting WebSocket connection, attempt #{}", reconnectCounter);
// Attempt to establish the WebSocket connection
if (connectSession()) {
logger.debug("WebSocket connection established, starting monitoring");
int aliveCounter = 0; // Counter for successful alive checks
// Inner loop to monitor the active WebSocket connection
while (isSocketConnectionAlive()) {
logger.debug(
"isSocketConnectionAlive is true, aliveCounter {}, (re)connectCounter {}, sleeping for {}s, SysApp Version {}, jetty {}, lastReceived {}ms ago",
aliveCounter++, reconnectCounter, BRIDGE_WEBSOCKET_KEEPALIVE, sysapVersion,
org.eclipse.jetty.util.Jetty.VERSION,
lastReceivedTime == 0 ? "nothing recieved yet"
: System.currentTimeMillis() - lastReceivedTime);
// Sleep for the keep-alive interval to periodically check the connection
TimeUnit.SECONDS.sleep(BRIDGE_WEBSOCKET_KEEPALIVE);
logger.debug("Sending keep-alive message {}", System.currentTimeMillis());
sendWebsocketKeepAliveMessage("keep-alive");
// Send keep-alive message or ping based on configuration
if (sendKeepAliveMessage) {
logger.debug("Sending keep-alive message, System.currentTimeMillis {}ms",
System.currentTimeMillis());
sendWebsocketKeepAliveMessage("keep-alive");
} else {
logger.debug("Sending ping message, System.currentTimeMillis {}ms",
System.currentTimeMillis());
sendWebsocketPing();
}
}
logger.debug("Socket connection closed - isSocketConnectionAlive == false");
} else {
// Log if the connection attempt failed
logger.debug("WebSocket connection attempt failed");
}
logger.debug("Socket connection closed");
reconnectDelay.set(BRIDGE_WEBSOCKET_RECONNECT_DELAY);
// Delay before the next reconnect attempt
logger.debug("Delaying (re)connect request by {} seconds", BRIDGE_WEBSOCKET_RECONNECT_DELAY);
TimeUnit.SECONDS.sleep(BRIDGE_WEBSOCKET_RECONNECT_DELAY);
} else {
logger.debug("httpConnectionOK NOT True, this should not happen");
logger.debug("Retrying in {} seconds", BRIDGE_WEBSOCKET_RECONNECT_DELAY);
TimeUnit.SECONDS.sleep(BRIDGE_WEBSOCKET_RECONNECT_DELAY);
}
} catch (InterruptedException e) {
// Handle thread interruption (e.g., during shutdown)
Thread.currentThread().interrupt();
logger.debug("WebSocket monitor thread interrupted as expected during shutdown");
} catch (IOException e) {
// Handle IO errors (e.g., from sendWebsocketKeepAliveMessage or sendWebsocketPing)
logger.warn("Error in WebSocket communication: {}", e.getMessage());
try {
// Delay before retrying after an IO error
logger.debug("Retrying after IO error in {} seconds", BRIDGE_WEBSOCKET_RECONNECT_DELAY);
TimeUnit.SECONDS.sleep(BRIDGE_WEBSOCKET_RECONNECT_DELAY);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
logger.debug("Interrupted during IO error recovery {}", ie.getMessage());
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.general-websocket-issue");
} catch (IOException e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.websocket-keep-alive-error");
}
// Log when the thread stops
logger.debug("WebSocket monitor thread stopped");
}
private boolean connectSession() throws InterruptedException {
int delay = reconnectDelay.get();
if (delay > 0) {
logger.debug("Delaying (re)connect request by {} seconds.", reconnectDelay);
logger.debug("Delaying (re)connect request by {} seconds.", delay);
TimeUnit.SECONDS.sleep(delay);
}
@ -778,15 +990,25 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
return false;
}
if (websocketSession == null) {
lock.lock();
try {
websocketSessionEstablished.await();
} finally {
lock.unlock();
// Wait for connection to be established or fail with a timeout
lock.lock();
try {
if (websocketSession == null) {
boolean established = websocketSessionEstablished.await(BRIDGE_WEBSOCKET_TIMEOUT, TimeUnit.SECONDS);
if (!established || websocketSession == null) {
logger.trace("WebSocket connection timed out or failed during establishment");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"@text/comm-error.general-websocket-issue");
reconnectDelay.set(BRIDGE_WEBSOCKET_RECONNECT_DELAY);
return false;
}
}
} finally {
lock.unlock();
}
logger.debug("WebSocket session successfully established");
reconnectDelay.set(0); // Reset delay on successful connection
return true;
}
}
@ -803,14 +1025,40 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
}
/**
* Get socket alive state
*
* @throws InterruptedException
* Send ping message to SysAp
*/
public boolean isSocketConnectionAlive() throws InterruptedException {
public void sendWebsocketPing() throws IOException {
Session localSession = websocketSession;
return (localSession != null) ? localSession.isOpen() : false;
if (localSession != null) {
localSession.getRemote().sendPing(ByteBuffer.wrap("ping".getBytes()));
}
}
/**
* Get socket alive state
*
* @throws InterruptedException
*/
public boolean isSocketConnectionAlive() {
Session localSession = websocketSession;
if (localSession == null) {
logger.debug("Socket connection is null");
return false;
} else if (!localSession.isOpen()) {
logger.debug("Socket connection is closed");
return false;
} else if (lastReceivedTime != 0) {
long timeSinceLastReceived = System.currentTimeMillis() - lastReceivedTime;
if (timeSinceLastReceived > BRIDGE_WEBSOCKET_TIMEOUT * 1000) {
logger.warn("No data received for {} ms, assuming connection is dead", timeSinceLastReceived);
localSession.close(StatusCode.ABNORMAL, "No data received");
return false;
}
return true;
}
return true;
}
/**
@ -819,7 +1067,8 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
@Override
public void onWebSocketClose(int statusCode, @Nullable String reason) {
websocketSession = null;
logger.debug("Socket Closed: [ {} ] {}", statusCode, reason);
lastReceivedTime = 0;
logger.warn("Socket Closed: [ {} ] {}", statusCode, reason);
}
/**
@ -831,12 +1080,29 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
if (localSession != null) {
websocketSession = localSession;
localSession.setIdleTimeout(2 * BRIDGE_WEBSOCKET_KEEPALIVE * 1000); // Unit is milliseconds,
// sendWebsocketPing() and
// sendWebsocketKeepAliveMessage() are
// called every
// BRIDGE_WEBSOCKET_KEEPALIVE, so the
// timeout should be at least 2 times
// that
logger.debug("WebSocket connection to SysAP established successfully, timeout: {} ms",
localSession.getIdleTimeout());
localSession.setIdleTimeout(-1);
// Fetch the SysAP version after a successful connection establishment
if (fetchSysapVersion()) {
logger.debug("SysAP version fetched successfully after reconnect: {}", sysapVersion);
updateStatus(ThingStatus.ONLINE); // Set the status to ONLINE
} else {
logger.warn("Failed to fetch SysAP version after successful reconnect");
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"@text/comm-error.fetch-version-error");
}
logger.debug("Socket Connected - Timeout {} - sesson: {}", localSession.getIdleTimeout(), session);
lastReceivedTime = System.currentTimeMillis();
} else {
logger.debug("Socket Connected - Timeout (invalid) - sesson: (invalid)");
logger.debug("Socket Connected - Timeout (invalid) - session: (invalid)");
}
lock.lock();
@ -852,13 +1118,31 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
*/
@Override
public void onWebSocketError(@Nullable Throwable cause) {
Session localSession = websocketSession;
// Log the error with details if available
if (cause != null) {
logger.warn("WebSocket error occurred: {}", cause.getLocalizedMessage());
} else {
logger.warn("WebSocket error occurred: unknown cause");
}
// Check and close the session if it is still open
if (localSession != null && localSession.isOpen()) {
try {
localSession.close(StatusCode.ABNORMAL, "Closed due to error");
logger.debug("WebSocket session closed due to error");
} catch (Exception e) {
logger.warn("Failed to close WebSocket session: {}", e.getMessage());
}
}
// Set the session to null to indicate it is no longer valid
websocketSession = null;
if (cause != null) {
logger.debug("Socket Error: {}", cause.getLocalizedMessage());
} else {
logger.debug("Socket Error: unknown");
}
// Update the thing status to OFFLINE with error details
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
"WebSocket connection failed: " + (cause != null ? cause.getMessage() : "unknown error"));
}
/**
@ -867,7 +1151,7 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
@Override
@NonNullByDefault({})
public void onWebSocketBinary(byte[] payload, int offset, int len) {
logger.debug("Binary message received via websocket");
logger.warn("Binary message received via websocket - It shall not happen with the free@home SysAp");
}
/**
@ -876,6 +1160,7 @@ public class FreeAtHomeBridgeHandler extends BaseBridgeHandler implements WebSoc
@Override
public void onWebSocketText(@Nullable String message) {
if (message != null) {
lastReceivedTime = System.currentTimeMillis();
if (message.toLowerCase(Locale.US).contains("bye")) {
Session localSession = websocketSession;

View File

@ -75,13 +75,13 @@ public class FreeAtHomeDeviceHandler extends BaseThingHandler implements FreeAtH
private final Logger logger = LoggerFactory.getLogger(FreeAtHomeDeviceHandler.class);
private FreeAtHomeDeviceDescription device = new FreeAtHomeDeviceDescription();
private FreeAtHomeChannelTypeProvider channelTypeProvider;
private TranslationProvider i18nProvider;
private Locale locale;
private final FreeAtHomeChannelTypeProvider channelTypeProvider;
private final TranslationProvider i18nProvider;
private final Locale locale;
private Bundle bundle;
private Map<ChannelUID, FreeAtHomeDatapointGroup> mapChannelUID = new HashMap<ChannelUID, FreeAtHomeDatapointGroup>();
private Map<String, ChannelUID> mapEventToChannelUID = new HashMap<String, ChannelUID>();
private final Map<ChannelUID, FreeAtHomeDatapointGroup> mapChannelUID = new HashMap<ChannelUID, FreeAtHomeDatapointGroup>();
private final Map<String, ChannelUID> mapEventToChannelUID = new HashMap<String, ChannelUID>();
public FreeAtHomeDeviceHandler(Thing thing, FreeAtHomeChannelTypeProvider channelTypeProvider,
TranslationProvider i18nProvider, LocaleProvider localeProvider) {
@ -305,10 +305,12 @@ public class FreeAtHomeDeviceHandler extends BaseThingHandler implements FreeAtH
}
}
@Override
public void onDeviceRemoved() {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.GONE);
}
@Override
public void onDeviceStateChanged(String event, String valueString) {
// Get the channle UID belonging to this event
ChannelUID channelUID = mapEventToChannelUID.get(event);
@ -499,8 +501,8 @@ public class FreeAtHomeDeviceHandler extends BaseThingHandler implements FreeAtH
// in case of output channel, register it for updates
if (outputDatapoint != null) {
String eventDatapointID = new String(device.getDeviceId() + "/" + channel.getChannelId() + "/"
+ outputDatapoint.getDatapointId());
String eventDatapointID = device.getDeviceId() + "/" + channel.getChannelId() + "/"
+ outputDatapoint.getDatapointId();
mapEventToChannelUID.put(eventDatapointID, channelUID);
}
@ -572,8 +574,8 @@ public class FreeAtHomeDeviceHandler extends BaseThingHandler implements FreeAtH
// in case of output channel, register it for updates
if (outputDatapoint != null) {
String eventDatapointID = new String(device.getDeviceId() + "/" + channel.getChannelId() + "/"
+ outputDatapoint.getDatapointId());
String eventDatapointID = device.getDeviceId() + "/" + channel.getChannelId() + "/"
+ outputDatapoint.getDatapointId();
mapEventToChannelUID.put(eventDatapointID, channelUID);
}

View File

@ -29,8 +29,11 @@ public class FidTranslationUtils {
public static final int FID_UNKNOWN = 0xFFFFAAFF; // Unknown
// free@home constants
// Function IDs https://developer.eu.mybuildings.abb.com/fah_cloud/reference/functionids
// Pairing IDs https://developer.eu.mybuildings.abb.com/fah_cloud/references/pairingids
public static final int FID_SWITCH_SENSOR = 0x0000; // Control element
public static final int FID_DIMMING_SENSOR = 0x0001; // Dimming sensor
public static final int FID_SHUTTER_SENSOR = 0x0002; // Shutter Sensor
public static final int FID_BLIND_SENSOR = 0x0003; // Blind sensor
public static final int FID_STAIRCASE_LIGHT_SENSOR = 0x0004; // Stairwell light sensor
public static final int FID_FORCE_ON_OFF_SENSOR = 0x0005; // Force On/Off sensor
@ -51,6 +54,8 @@ public class FidTranslationUtils {
public static final int FID_UNDERFLOOR_HEATING = 0x0015; // Underfloor heating
public static final int FID_FAN_COIL = 0x0016; // Fan Coil
public static final int FID_TWO_LEVEL_CONTROLLER = 0x0017; // Two-level controller
public static final int FID_PUSH_BUTTON_SENSOR = 0x0018; // Push button
public static final int FID_RING_INDICATION_SENSOR = 0x0019; // Ring indicator
public static final int FID_DES_DOOR_OPENER_ACTUATOR = 0x001A; // Door opener
public static final int FID_PROXY = 0x001B; // Proxy
public static final int FID_DES_LEVEL_CALL_ACTUATOR = 0x001D; // Door Map.entry System Call Level Actuator
@ -60,15 +65,19 @@ public class FidTranslationUtils {
public static final int FID_DES_LIGHT_SWITCH_ACTUATOR = 0x0021; // Corridor light
public static final int FID_ROOM_TEMPERATURE_CONTROLLER_MASTER_WITHOUT_FAN = 0x0023; // Room temperature controller
public static final int FID_COOLING_ACTUATOR = 0x0024; // Cooling mode
public static final int FID_DAY_NIGHT_SENSOR = 0x0025; // Day/night sensor
public static final int FID_HEATING_ACTUATOR = 0x0027; // Heating mode
public static final int FID_FORCE_UP_DOWN_SENSOR = 0x0028; // Force-position blind
public static final int FID_HEATING_COOLING_ACTUATOR = 0x0029; // Auto. heating/cooling mode
public static final int FID_HEATING_COOLING_SENSOR = 0x002A; // Switchover heating/cooling
public static final int FID_DES_DEVICE_SETTINGS = 0x002B; // Device settings
public static final int FID_SACE_BLIND_ACTUATOR = 0x002C; // Space blind
public static final int FID_RGB_SENSOR = 0x002D; // RGB sensor
public static final int FID_RGB_W_ACTUATOR = 0x002E; // Dim actuator
public static final int FID_RGB_ACTUATOR = 0x002F; // Dim actuator
public static final int FID_PANEL_SWITCH_SENSOR = 0x0030; // Control element
public static final int FID_PANEL_DIMMING_SENSOR = 0x0031; // Dimming sensor
public static final int FID_PANEL_SHUTTER_SENSOR = 0x0032; // Shutter
public static final int FID_PANEL_BLIND_SENSOR = 0x0033; // Blind sensor
public static final int FID_PANEL_STAIRCASE_LIGHT_SENSOR = 0x0034; // Stairwell light sensor
public static final int FID_PANEL_FORCE_ON_OFF_SENSOR = 0x0035; // Force On/Off sensor
@ -83,6 +92,7 @@ public class FidTranslationUtils {
public static final int FID_ADDITIONAL_HEATING_ACTUATOR = 0x003D; // Add. stage for heating mode
public static final int FID_RADIATOR_ACTUATOR_MASTER = 0x003E; // Radiator thermostate
public static final int FID_RADIATOR_ACTUATOR_SLAVE = 0x003F; // Room temperature controller extension unit
public static final int FID_COLORTEMPERATURE_ACTUATOR = 0x0040; // Color temperature
public static final int FID_BRIGHTNESS_SENSOR = 0x0041; // Brightness sensor
public static final int FID_RAIN_SENSOR = 0x0042; // Rain sensor
public static final int FID_TEMPERATURE_SENSOR = 0x0043; // Temperature sensor
@ -93,13 +103,15 @@ public class FidTranslationUtils {
public static final int FID_FCA_2_PIPE_HEATING_COOLING = 0x0049; // Auto. heating/cooling mode
public static final int FID_FCA_4_PIPE_HEATING_AND_COOLING = 0x004A; // Two valves for heating and cooling
public static final int FID_WINDOW_DOOR_ACTUATOR = 0x004B; // Window/Door
public static final int FID_INVERTER_INFO = 0x004E; // ABC
public static final int FID_METER_INFO = 0x004F; // ABD
public static final int FID_BATTERY_INFO = 0x0050; // ACD
public static final int FID_INVERTER_INFO = 0x004E; // Inverter information
public static final int FID_METER_INFO = 0x004F; // Meter information
public static final int FID_BATTERY_INFO = 0x0050; // Battery information
public static final int FID_PANEL_TIMER_PROGRAM_SWITCH_SENSOR = 0x0051; // Timer program switch sensor
public static final int FID_SAFETY_SENSOR = 0x0053; // Safety sensor
public static final int FID_DOMUSTECH_ZONE = 0x0055; // Zone
public static final int FID_CENTRAL_HEATING_ACTUATOR = 0x0056; // Central heating actuator
public static final int FID_CENTRAL_COOLING_ACTUATOR = 0x0057; // Central cooling actuator
public static final int FID_LINK_ACTUATOR = 0x0058; // Link actuator
public static final int FID_HOUSE_KEEPING = 0x0059; // Housekeeping
public static final int FID_MEDIA_PLAYER = 0x005A; // Media Player
public static final int FID_PANEL_ROOM_TEMPERATURE_CONTROLLER_SLAVE_FOR_BATTERY_DEVICE = 0x005B; // Panel Room
@ -107,6 +119,10 @@ public class FidTranslationUtils {
// Controller Slave
// For Battery
// Device
public static final int FID_WELCOME_IP_MUTE_SENSOR = 0x005C; // Welcome-IP mute sensor
public static final int FID_WELCOME_IP_MUTE_ACTUATOR = 0x005D; // Welcome-IP mute
public static final int FID_WELCOME_IP_DOOR_OPEN_SENSOR = 0x005E; // Welcome-IP doors open sensor
public static final int FID_WELCOME_IP_SWITCH_SENSOR = 0x005F; // Welcome-IP switch
public static final int FID_PANEL_MEDIA_PLAYER_SENSOR = 0x0060; // Media Player Sensor
public static final int FID_BLIND_ACTUATOR = 0x0061; // Roller blind actuator
public static final int FID_ATTIC_WINDOW_ACTUATOR = 0x0062; // Attic window actuator
@ -125,6 +141,7 @@ public class FidTranslationUtils {
public static final int FID_COFFEE_MACHINE = 0x006F; // Coffee machine
public static final int FID_FRIDGE_FREEZER = 0x0070; // Fridge/Freezer
public static final int FID_TIMER_PROGRAM_OR_ALERT_SWITCH_SENSOR = 0x0071; // Timer program switch sensor
public static final int FID_WELCOME_IP_BELL_INDICATOR_SENSOR = 0x0072; // Welcome-IP bell indicator
public static final int FID_CEILING_FAN_ACTUATOR = 0x0073; // Ceiling fan actuator
public static final int FID_CEILING_FAN_SENSOR = 0x0074; // Ceiling fan sensor
public static final int FID_SPLIT_UNIT_GATEWAY = 0x0075; // Room temperature controller with fan speed level
@ -148,6 +165,10 @@ public class FidTranslationUtils {
public static final int FID_ADDITIONAL_COOLING_ACTUATOR = 0x0087; // Add. stage for cooling mode
public static final int FID_TWO_LEVEL_HEATING_ACTUATOR = 0x0088; // Two Level Heating Actuator
public static final int FID_TWO_LEVEL_COOLING_ACTUATOR = 0x0089; // Two Level Cooling Actuator
public static final int FID_DOOR_LOCK_SENSOR = 0x008A; // Door lock sensor
public static final int FID_DOOR_LOCK_ACTUATOR = 0x008B; // Door lock actuator
public static final int FID_AC_ROUTING = 0x008C; // AC routing
public static final int FID_EXTERNAL_SIREN = 0x008D; // External siren
public static final int FID_GLOBAL_ZONE = 0x008E; // Zone
public static final int FID_VOLUME_UP_SENSOR = 0x008F; // Volume up
public static final int FID_VOLUME_DOWN_SENSOR = 0x0090; // Volume down
@ -168,6 +189,7 @@ public class FidTranslationUtils {
public static final int FID_DOMUSCURTAINDETECTOR = 0x009F; // External IR Sensor Curtain
public static final int FID_DOMUSSMOKEDETECTOR = 0x00A0; // Smoke Detector
public static final int FID_DOMUSFLOODDETECTOR = 0x00A1; // Flood Detection
public static final int FID_HOB = 0x00A2; // HOB
public static final int FID_PANEL_SUG_SENSOR = 0x00A3; // Sensor for air-conditioning unit
public static final int FID_TWO_LEVEL_HEATING_COOLING_ACTUATOR = 0x00A4; // Two-point controller for heating or
// cooling
@ -175,27 +197,47 @@ public class FidTranslationUtils {
public static final int FID_WALLBOX = 0x00A6; // Wallbox
public static final int FID_PANEL_WALLBOX = 0x00A7; // Wallbox
public static final int FID_DOOR_LOCK_CONTROL = 0x00A8; // Door lock control
public static final int FID_DOOR_LOCK_SETTINGS = 0x00A9; // Door lock settings
public static final int FID_VRV_GATEWAY = 0x00AA; // Room temperature controller with fan speed level
public static final int FID_CO_2 = 0x00BA; // Co2
public static final int FID_VOC = 0x00BB; // Voc
public static final int FID_AIRQUALITY_SENSOR = 0x00BD; // Airquality sensor
public static final int FID_SWITCH_SENSOR_PUSHBUTTON_TYPE0 = 0x1008; // Switch sensor push button
public static final int FID_SWITCH_SENSOR_PUSHBUTTON_TYPE1 = 0x1009; // Switch sensor push button
public static final int FID_SWITCH_SENSOR_PUSHBUTTON_TYPE2 = 0x100A; // Switch sensor push button
public static final int FID_SWITCH_SENSOR_PUSHBUTTON_TYPE3 = 0x100B; // Switch sensor push button
public static final int FID_SWITCH_SENSOR_PUSHBUTTON_TYPE4 = 0x100C; // Switch sensor push button
public static final int FID_SWITCH_SENSOR_PUSHBUTTON_TYPE5 = 0x100D; // Switch sensor push button
public static final int FID_SWITCH_SENSOR_PUSHBUTTON_TYPE6 = 0x100E; // Switch sensor push button
public static final int FID_SWITCH_SENSOR_PUSHBUTTON_TYPE7 = 0x100F; // Switch sensor push button
public static final int FID_DIMMING_SENSOR_PUSHBUTTON_TYPE0 = 0x1018; // Dimming sensor push button
public static final int FID_DIMMING_SENSOR_PUSHBUTTON_TYPE1 = 0x1019; // Dimming sensor push button
public static final int FID_DIMMING_SENSOR_PUSHBUTTON_TYPE2 = 0x101A; // Dimming sensor push button
public static final int FID_DIMMING_SENSOR_PUSHBUTTON_TYPE3 = 0x101B; // Dimming sensor push button
public static final int FID_DIMMING_SENSOR_PUSHBUTTON_TYPE4 = 0x101C; // Dimming sensor push button
public static final int FID_DIMMING_SENSOR_PUSHBUTTON_TYPE5 = 0x101D; // Dimming sensor push button
public static final int FID_DIMMING_SENSOR_PUSHBUTTON_TYPE6 = 0x101E; // Dimming sensor push button
public static final int FID_DIMMING_SENSOR_PUSHBUTTON_TYPE7 = 0x101F; // Dimming sensor push button
public static final int FID_MOVEMENT_DETECTOR_FLEX = 0x1090; // Movement detector flex
public static final int FID_MOVEMENT_DETECTOR_TYPE0 = 0x1090; // Movement Detector
public static final int FID_DIMMING_ACTUATOR_FLEX = 0x1810; // Switch actuator flex
public static final int FID_DIMMING_ACTUATOR_TYPE0 = 0x1810; // Dim actuator
public static final int FID_BLIND_ACTUATOR_WIRELESS = 0x1821; // Wireless blind actuator
public static final int FID_SCENE_TRIGGER = 0x4800; // Scene trigger
public static final int FID_RULE_SWITCH = 0x4A00; // Scene trigger
// FID added based on tests
public static final int FID_AIRQUALITYSENSOR_PRESSURE = 0x0E017;
public static final int FID_AIRQUALITYSENSOR_CO2 = 0x0E018;
public static final int FID_AIRQUALITYSENSOR_CO = 0x0E019;
public static final int FID_AIRQUALITYSENSOR_NO2 = 0x0E01A;
public static final int FID_AIRQUALITYSENSOR_O3 = 0x0E01B;
public static final int FID_AIRQUALITYSENSOR_PM10 = 0x0E01C;
public static final int FID_AIRQUALITYSENSOR_PM25 = 0x0E01D;
public static final int FID_AIRQUALITYSENSOR_VOC = 0x0E01E;
public static final int FID_AIRQUALITYSENSOR_HUMIDITY = 0x0B03F;
public static final int FID_MOVEMENT_DETECTOR_FLEX = 0x1090;
public static final int FID_DIMMING_ACTUATOR_FLEX = 0x1810;
public static final int FID_RULE_SWITCH = 0x4A00; // Rule Switch
public static final int FID_AIRQUALITYSENSOR_HUMIDITY = 0xB03F; // Air quality sensor humidity
public static final int FID_AIRQUALITYSENSOR_PRESSURE = 0xE017; // Air quality sensor Pressure
public static final int FID_AIRQUALITYSENSOR_CO2 = 0xE018; // Air quality sensor CO2
public static final int FID_AIRQUALITYSENSOR_CO = 0xE019; // Air quality sensor CO
public static final int FID_AIRQUALITYSENSOR_NO2 = 0xE01A; // Air quality sensor NO2
public static final int FID_AIRQUALITYSENSOR_O3 = 0xE01B; // Air quality sensor O3
public static final int FID_AIRQUALITYSENSOR_PM10 = 0xE01C; // Air quality sensor PM10
public static final int FID_AIRQUALITYSENSOR_PM25 = 0xE01D; // Air quality sensor PM25
public static final int FID_AIRQUALITYSENSOR_VOC = 0xE01E; // Air quality sensor VOC
private static final Map<String, String> MAP_FUNCTION_ID = Map.ofEntries(Map.entry("0x0000", "fid-control-element"), // FID_SWITCH_SENSOR
Map.entry("0x0001", "fid-dimming-sensor"), // FID_DIMMING_SENSOR
Map.entry("0x0002", "fid-shutter-sensor"), // FID_SHUTTER_SENSOR
Map.entry("0x0003", "fid-blind-sensor"), // FID_BLIND_SENSOR
Map.entry("0x0004", "fid-stairwell-light-sensor"), // FID_STAIRCASE_LIGHT_SENSOR
Map.entry("0x0005", "fid-force-on/off-sensor"), // FID_FORCE_ON_OFF_SENSOR
@ -214,6 +256,8 @@ public class FidTranslationUtils {
Map.entry("0x0015", "fid-underfloor-heating"), // FID_UNDERFLOOR_HEATING
Map.entry("0x0016", "fid-fan-coil"), // FID_FAN_COIL
Map.entry("0x0017", "fid-two-level-controller"), // FID_TWO_LEVEL_CONTROLLER
Map.entry("0x0018", "fid-push-button"), // FID_PUSH_BUTTON_SENSOR
Map.entry("0x0019", "fid-ring-indicator"), // FID_RING_INDICATION_SENSOR
Map.entry("0x001A", "fid-door-opener"), // FID_DES_DOOR_OPENER_ACTUATOR
Map.entry("0x001B", "fid-proxy"), // FID_PROXY
Map.entry("0x001D", "fid-door-map.entry-system-call-level-actuator"), // FID_DES_LEVEL_CALL_ACTUATOR
@ -223,15 +267,19 @@ public class FidTranslationUtils {
Map.entry("0x0021", "fid-corridor-light"), // FID_DES_LIGHT_SWITCH_ACTUATOR
Map.entry("0x0023", "fid-room-temperature-controller"), // FID_ROOM_TEMPERATURE_CONTROLLER_MASTER_WITHOUT_FAN
Map.entry("0x0024", "fid-cooling-mode"), // FID_COOLING_ACTUATOR
Map.entry("0x0025", "fid-day/night-sensor"), // FID_DAY_NIGHT_SENSOR
Map.entry("0x0027", "fid-heating-mode"), // FID_HEATING_ACTUATOR
Map.entry("0x0028", "fid-force-position-blind"), // FID_FORCE_UP_DOWN_SENSOR
Map.entry("0x0029", "fid-auto.-heating/cooling-mode"), // FID_HEATING_COOLING_ACTUATOR
Map.entry("0x002A", "fid-switchover-heating/cooling"), // FID_HEATING_COOLING_SENSOR
Map.entry("0x002B", "fid-device-settings"), // FID_DES_DEVICE_SETTINGS
Map.entry("0x002C", "fid-space-blind"), // FID_SACE_BLIND_ACTUATOR
Map.entry("0x002D", "fid-rgb-sensor"), // FID_RGB_SENSOR
Map.entry("0x002E", "fid-dim-actuator"), // FID_RGB_W_ACTUATOR
Map.entry("0x002F", "fid-dim-actuator"), // FID_RGB_ACTUATOR
Map.entry("0x0030", "fid-control-element"), // FID_PANEL_SWITCH_SENSOR
Map.entry("0x0031", "fid-dimming-sensor"), // FID_PANEL_DIMMING_SENSOR
Map.entry("0x0032", "fid-shutter"), // FID_PANEL_SHUTTER_SENSOR
Map.entry("0x0033", "fid-blind-sensor"), // FID_PANEL_BLIND_SENSOR
Map.entry("0x0034", "fid-stairwell-light-sensor"), // FID_PANEL_STAIRCASE_LIGHT_SENSOR
Map.entry("0x0035", "fid-force-on/off-sensor"), // FID_PANEL_FORCE_ON_OFF_SENSOR
@ -245,6 +293,7 @@ public class FidTranslationUtils {
Map.entry("0x003D", "fid-add.-stage-for-heating-mode"), // FID_ADDITIONAL_HEATING_ACTUATOR
Map.entry("0x003E", "fid-radiator-thermostate"), // FID_RADIATOR_ACTUATOR_MASTER
Map.entry("0x003F", "fid-room-temperature-controller-extension-unit"), // FID_RADIATOR_ACTUATOR_SLAVE
Map.entry("0x0040", "fid-color-temperature"), // FID_COLORTEMPERATURE_ACTUATOR
Map.entry("0x0041", "fid-brightness-sensor"), // FID_BRIGHTNESS_SENSOR
Map.entry("0x0042", "fid-rain-sensor"), // FID_RAIN_SENSOR
Map.entry("0x0043", "fid-temperature-sensor"), // FID_TEMPERATURE_SENSOR
@ -255,16 +304,22 @@ public class FidTranslationUtils {
Map.entry("0x0049", "fid-auto.-heating/cooling-mode"), // FID_FCA_2_PIPE_HEATING_COOLING
Map.entry("0x004A", "fid-two-valves-for-heating-and-cooling"), // FID_FCA_4_PIPE_HEATING_AND_COOLING
Map.entry("0x004B", "fid-window/door"), // FID_WINDOW_DOOR_ACTUATOR
Map.entry("0x004E", "fid-abc"), // FID_INVERTER_INFO
Map.entry("0x004F", "fid-abd"), // FID_METER_INFO
Map.entry("0x0050", "fid-acd"), // FID_BATTERY_INFO
Map.entry("0x004E", "fid-inverter-information"), // FID_INVERTER_INFO
Map.entry("0x004F", "fid-meter-information"), // FID_METER_INFO
Map.entry("0x0050", "fid-battery-information"), // FID_BATTERY_INFO
Map.entry("0x0051", "fid-timer-program-switch-sensor"), // FID_PANEL_TIMER_PROGRAM_SWITCH_SENSOR
Map.entry("0x0053", "fid-safety-sensor"), // FID_SAFETY_SENSOR
Map.entry("0x0055", "fid-zone"), // FID_DOMUSTECH_ZONE
Map.entry("0x0056", "fid-central-heating-actuator"), // FID_CENTRAL_HEATING_ACTUATOR
Map.entry("0x0057", "fid-central-cooling-actuator"), // FID_CENTRAL_COOLING_ACTUATOR
Map.entry("0x0058", "fid-link-actuator"), // FID_LINK_ACTUATOR
Map.entry("0x0059", "fid-housekeeping"), // FID_HOUSE_KEEPING
Map.entry("0x005A", "fid-media-player"), // FID_MEDIA_PLAYER
Map.entry("0x005B", "fid-panel-room-temperature-controller-slave-for-battery-device"), // FID_PANEL_ROOM_TEMPERATURE_CONTROLLER_SLAVE_FOR_BATTERY_DEVICE
Map.entry("0x005C", "fid-welcome-ip-mute-sensor"), // FID_WELCOME_IP_MUTE_SENSOR
Map.entry("0x005D", "fid-welcome-ip-mute"), // FID_WELCOME_IP_MUTE_ACTUATOR
Map.entry("0x005E", "fid-welcome-ip-doors-open-sensor"), // FID_WELCOME_IP_DOOR_OPEN_SENSOR
Map.entry("0x005F", "fid-welcome-ip-switch"), // FID_WELCOME_IP_SWITCH_SENSOR
Map.entry("0x0060", "fid-media-player-sensor"), // FID_PANEL_MEDIA_PLAYER_SENSOR
Map.entry("0x0061", "fid-roller-blind-actuator"), // FID_BLIND_ACTUATOR
Map.entry("0x0062", "fid-attic-window-actuator"), // FID_ATTIC_WINDOW_ACTUATOR
@ -283,6 +338,7 @@ public class FidTranslationUtils {
Map.entry("0x006F", "fid-coffee-machine"), // FID_COFFEE_MACHINE
Map.entry("0x0070", "fid-fridge/freezer"), // FID_FRIDGE_FREEZER
Map.entry("0x0071", "fid-timer-program-switch-sensor"), // FID_TIMER_PROGRAM_OR_ALERT_SWITCH_SENSOR
Map.entry("0x0072", "fid-welcome-ip-bell-indicator"), // FID_WELCOME_IP_BELL_INDICATOR_SENSOR
Map.entry("0x0073", "fid-ceiling-fan-actuator"), // FID_CEILING_FAN_ACTUATOR
Map.entry("0x0074", "fid-ceiling-fan-sensor"), // FID_CEILING_FAN_SENSOR
Map.entry("0x0075", "fid-room-temperature-controller-with-fan-speed-level"), // FID_SPLIT_UNIT_GATEWAY
@ -306,6 +362,10 @@ public class FidTranslationUtils {
Map.entry("0x0087", "fid-add.-stage-for-cooling-mode"), // FID_ADDITIONAL_COOLING_ACTUATOR
Map.entry("0x0088", "fid-two-level-heating-actuator"), // FID_TWO_LEVEL_HEATING_ACTUATOR
Map.entry("0x0089", "fid-two-level-cooling-actuator"), // FID_TWO_LEVEL_COOLING_ACTUATOR
Map.entry("0x008A", "fid-door-lock-sensor"), // FID_DOOR_LOCK_SENSOR
Map.entry("0x008B", "fid-door-lock-actuator"), // FID_DOOR_LOCK_ACTUATOR
Map.entry("0x008C", "fid-ac-routing"), // FID_AC_ROUTING
Map.entry("0x008D", "fid-external-siren"), // FID_EXTERNAL_SIREN
Map.entry("0x008E", "fid-zone"), // FID_GLOBAL_ZONE
Map.entry("0x008F", "fid-volume-up"), // FID_VOLUME_UP_SENSOR
Map.entry("0x0090", "fid-volume-down"), // FID_VOLUME_DOWN_SENSOR
@ -326,15 +386,42 @@ public class FidTranslationUtils {
Map.entry("0x009F", "fid-external-ir-sensor-curtain"), // FID_DOMUSCURTAINDETECTOR
Map.entry("0x00A0", "fid-smoke-detector"), // FID_DOMUSSMOKEDETECTOR
Map.entry("0x00A1", "fid-flood-detection"), // FID_DOMUSFLOODDETECTOR
Map.entry("0x00A2", "fid-hob"), // FID_HOB
Map.entry("0x00A3", "fid-sensor-for-air-conditioning-unit"), // FID_PANEL_SUG_SENSOR
Map.entry("0x00A4", "fid-two-point-controller-for-heating-or-cooling"), // FID_TWO_LEVEL_HEATING_COOLING_ACTUATOR
Map.entry("0x00A5", "fid-slave-thermostat"), // FID_PANEL_THERMOSTAT_CONTROLLER_SLAVE
Map.entry("0x00A6", "fid-wallbox"), // FID_WALLBOX
Map.entry("0x00A7", "fid-wallbox"), // FID_PANEL_WALLBOX
Map.entry("0x00A8", "fid-door-lock-control"), // FID_DOOR_LOCK_CONTROL
Map.entry("0x00A9", "fid-door-lock-settings"), // FID_DOOR_LOCK_SETTINGS
Map.entry("0x00AA", "fid-room-temperature-controller-with-fan-speed-level"), // FID_VRV_GATEWAY
Map.entry("0x00BA", "fid-co2"), // FID_CO_2
Map.entry("0x00BB", "fid-voc"), // FID_VOC
Map.entry("0x00BD", "fid-airquality-sensor"), // FID_AIRQUALITY_SENSOR
Map.entry("0x1008", "fid-switch-sensor-push-button"), // FID_SWITCH_SENSOR_PUSHBUTTON_TYPE0
Map.entry("0x1009", "fid-switch-sensor-push-button"), // FID_SWITCH_SENSOR_PUSHBUTTON_TYPE1
Map.entry("0x100A", "fid-switch-sensor-push-button"), // FID_SWITCH_SENSOR_PUSHBUTTON_TYPE2
Map.entry("0x100B", "fid-switch-sensor-push-button"), // FID_SWITCH_SENSOR_PUSHBUTTON_TYPE3
Map.entry("0x100C", "fid-switch-sensor-push-button"), // FID_SWITCH_SENSOR_PUSHBUTTON_TYPE4
Map.entry("0x100D", "fid-switch-sensor-push-button"), // FID_SWITCH_SENSOR_PUSHBUTTON_TYPE5
Map.entry("0x100E", "fid-switch-sensor-push-button"), // FID_SWITCH_SENSOR_PUSHBUTTON_TYPE6
Map.entry("0x100F", "fid-switch-sensor-push-button"), // FID_SWITCH_SENSOR_PUSHBUTTON_TYPE7
Map.entry("0x1018", "fid-dimming-sensor-push-button"), // FID_DIMMING_SENSOR_PUSHBUTTON_TYPE0
Map.entry("0x1019", "fid-dimming-sensor-push-button"), // FID_DIMMING_SENSOR_PUSHBUTTON_TYPE1
Map.entry("0x101A", "fid-dimming-sensor-push-button"), // FID_DIMMING_SENSOR_PUSHBUTTON_TYPE2
Map.entry("0x101B", "fid-dimming-sensor-push-button"), // FID_DIMMING_SENSOR_PUSHBUTTON_TYPE3
Map.entry("0x101C", "fid-dimming-sensor-push-button"), // FID_DIMMING_SENSOR_PUSHBUTTON_TYPE4
Map.entry("0x101D", "fid-dimming-sensor-push-button"), // FID_DIMMING_SENSOR_PUSHBUTTON_TYPE5
Map.entry("0x101E", "fid-dimming-sensor-push-button"), // FID_DIMMING_SENSOR_PUSHBUTTON_TYPE6
Map.entry("0x101F", "fid-dimming-sensor-push-button"), // FID_DIMMING_SENSOR_PUSHBUTTON_TYPE7
Map.entry("0x1090", "fid-movement-detector-flex"), // FID_MOVEMENT_DETECTOR_FLEX
Map.entry("0x1090", "fid-movement-detector"), // FID_MOVEMENT_DETECTOR_TYPE0
Map.entry("0x1810", "fid-switch-actuator-flex"), // FID_DIMMING_ACTUATOR_FLEX
Map.entry("0x1810", "fid-dim-actuator"), // FID_DIMMING_ACTUATOR_TYPE0
Map.entry("0x1821", "fid-wireless-blind-actuator"), // FID_BLIND_ACTUATOR_WIRELESS
Map.entry("0x4800", "fid-scene-trigger"), // FID_SCENE_TRIGGER
Map.entry("0x4A00", "fid-rule-switch"), // FID_RULE_SWITCH
Map.entry("0xB03F", "fid-air-quality-sensor-humidity"), // FID_AIRQUALITYSENSOR_HUMIDITY
Map.entry("0xE017", "fid-air-quality-sensor-pressure"), // FID_AIRQUALITYSENSOR_PRESSURE
Map.entry("0xE018", "fid-air-quality-sensor-co2"), // FID_AIRQUALITYSENSOR_CO2
Map.entry("0xE019", "fid-air-quality-sensor-co"), // FID_AIRQUALITYSENSOR_CO
@ -342,10 +429,8 @@ public class FidTranslationUtils {
Map.entry("0xE01B", "fid-air-quality-sensor-o3"), // FID_AIRQUALITYSENSOR_O3
Map.entry("0xE01C", "fid-air-quality-sensor-pm10"), // FID_AIRQUALITYSENSOR_PM10
Map.entry("0xE01D", "fid-air-quality-sensor-pm25"), // FID_AIRQUALITYSENSOR_PM25
Map.entry("0xE01E", "fid-air-quality-sensor-voc"), // FID_AIRQUALITYSENSOR_VOC
Map.entry("0xB03F", "fid-air-quality-sensor-humidity"), // FID_AIRQUALITYSENSOR_HUMIDITY
Map.entry("0x1090", "fid-movement-detector-flex"), // FID_MOVEMENT_DETECTOR_FLEX
Map.entry("0x1810", "fid-dim-actuator-flex") // FID_SWITCH_ACTUATOR_FLEX
Map.entry("0xE01E", "fid-air-quality-sensor-voc") // FID_AIRQUALITYSENSOR_VOC
);
@Nullable

View File

@ -28,7 +28,7 @@ import org.eclipse.jdt.annotation.Nullable;
public class FreeAtHomeHttpCommunicationException extends Exception {
private static final long serialVersionUID = -817364286035448863L;
private String errorMessage = "Unknown_Exception";
private int errorCode;
private final int errorCode;
public FreeAtHomeHttpCommunicationException(int errorCode, String message) {
super(message);
@ -37,6 +37,7 @@ public class FreeAtHomeHttpCommunicationException extends Exception {
this.errorCode = errorCode;
}
@Override
public @Nullable String getMessage() {
return this.errorMessage;
}

View File

@ -5,6 +5,6 @@
<type>binding</type>
<name>FreeAtHome Binding</name>
<description>This is the binding for free@home system.</description>
<description>This is the binding for Busch Jaeger (alternativ Vendor ABB) free@home system.</description>
<connection>local</connection>
</addon:addon>

View File

@ -1,7 +1,7 @@
# add-on
addon.freeathome.name = FreeAtHome Binding
addon.freeathome.description = This is the binding for free@home system.
addon.freeathome.description = This is the binding for Busch Jaeger (alternativ Vendor ABB) free@home system.
# thing types
@ -14,12 +14,16 @@ thing-type.freeathome.gateway.description = This gateway represents the free@hom
thing-type.config.freeathome.device.deviceId.label = Device Id
thing-type.config.freeathome.device.deviceId.description = This is the unique id of the free@home device (Please do not modify after the Thing is generated)
thing-type.config.freeathome.gateway.group.advanced_com_settings.label = Advanced Communication Settings
thing-type.config.freeathome.gateway.group.advanced_com_settings.description = Detailed settings for SysAp communication behavior
thing-type.config.freeathome.gateway.group.identification.label = SysAP Setting
thing-type.config.freeathome.gateway.group.identification.description = SysAP network address and user settings
thing-type.config.freeathome.gateway.ipAddress.label = Sysap IP Address
thing-type.config.freeathome.gateway.ipAddress.description = IP Address of the Busch-Jaeger Gateway
thing-type.config.freeathome.gateway.password.label = Password
thing-type.config.freeathome.gateway.password.description = Password for gateway
thing-type.config.freeathome.gateway.sendKeepAliveMessage.label = Send keep-alive message to SysAp
thing-type.config.freeathome.gateway.sendKeepAliveMessage.description = Older SysAp might require a keep-alive message over the socket instead of a ping message.
thing-type.config.freeathome.gateway.username.label = User Name
thing-type.config.freeathome.gateway.username.description = The login name
@ -29,6 +33,7 @@ comm-error.not-able-open-httpconnection = Cannot open http connection, wrong pas
comm-error.http-wrongpass-or-ip = Cannot open http connection, wrong password or IP address
comm-error.not-able-open-websocketconnection = Cannot open websocket connection
comm-error.general-websocket-issue = General issue in websocket connection
comm-error.fetch-version-error = Connected, but failed to fetch SysAP version
comm-error.websocket-keep-alive-error = Websocket keep alive error
comm-error.wrong-credentials = Wrong credentials for SysAP
comm-error.error-in-sysap-com = Error in SysAp communication

View File

@ -16,6 +16,12 @@
<advanced>false</advanced>
</parameter-group>
<parameter-group name="advanced_com_settings">
<label>Advanced Communication Settings</label>
<description>Detailed settings for SysAp communication behavior</description>
<advanced>true</advanced>
</parameter-group>
<parameter name="ipAddress" type="text" required="true" groupName="identification">
<context>network-address</context>
<label>Sysap IP Address</label>
@ -31,6 +37,14 @@
<description>Password for gateway</description>
</parameter>
<parameter name="sendKeepAliveMessage" type="boolean" required="false" groupName="identification">
<label>Send keep-alive message to SysAp</label>
<context>password</context>
<description>Older SysAp might require a keep-alive message over the socket instead of a ping message.</description>
<default>false</default>
<advanced>true</advanced>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>