added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.neohub</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-addons

View File

@@ -0,0 +1,176 @@
# NeoHub Binding
This is a binding for integrating [Heatmiser](https://www.heatmiser.com) room and underfloor heating control products.
The NeoHub (bridge) binding allows you to connect openHAB via TCP/IP to Heatmiser's NeoHub and integrate your Heatmiser smart thermostats, smart plugs, and accessories.
![NeoHub](doc/neohub-2.jpg)
## Supported Things
The binding supports the following types of Thing..
| Thing Type | Description |
|----------------------|-------------------------------------------------------------------------------------------|
| NeoHub | The Heatmiser NeoHub bridge which is used to communicate with NeoStat and NeoPlug devices |
| NeoStat | Heatmiser Neostat Smart Thermostat |
| NeoPlug | Heatmiser NeoPlug Smart Plug |
| NeoContact | Heatmiser Contact Sensor, wireless door or window contact |
| NeoTemperatureSensor | Heatmiser Wireless Air Sensor, wireless temperature sensor |
## Discovery
You have to manually create a single (Bridge) Thing for the NeoHub, and enter the required Configuration Parameters (see Thing Configuration for NeoHub below).
If the Configuration Parameters are all valid, then the NeoHub Thing will automatically attempt to connect and sign on to the hub.
If the sign on succeeds, the Thing will indicate its status as Online, otherwise it will show an error status.
Once the NeoHub Thing has been created and it has successfully signed on, it will automatically interrogate the HeoHub to discover all the respective Heatmiser device Things that are connected to it.
If in the future, you add additional Heatmiser devices to your system, the binding will discover them too.
## Thing Configuration for "NeoHub"
The NeoHub Thing connects to the hub (bridge) to communicate with any respective connected Heatmiser device Things.
It signs on to the hub using the supplied connection parameters, and it polls the hub at regular intervals to read and write the data for each Heatmiser device.
The NeoHub supports two Application Programming Interfaces "API" (an older "legacy" one, and a modern one), and this binding can use either of them to communicate with it.
Before the binding can communicate with the hub, the following Configuration Parameters must be entered.
| Configuration Parameter | Description |
|-------------------------|---------------------------------------------------------------------------------------------|
| hostName | Host name (IP address) of the NeoHub (example 192.168.1.123) |
| portNumber | Port number of the NeoHub (Default=4242) |
| pollingInterval | Time (seconds) between polling requests to the NeoHub (Min=4, Max=60, Default=60) |
| socketTimeout | Time (seconds) to allow for TCP socket connections to the hub to succeed (Min=4, Max=20, Default=5) |
| preferLegacyApi | Prefer if the binding should use the legacy API; this only works so long as the legacy API is still supported; otherwise the binding will switch to the new API anyway (Default=false) |
## Thing Configuration for "NeoStat" and "NeoPlug"
The NeoHub Thing connects to the hub (bridge) to communicate with any Heatmiser devices that are connected to it.
Each such Heatmiser device is identified by means of a unique device name in the hub.
The device name is automatically discovered by the NeoHub Thing, and it is also visible (and changeable) via the Heatmiser App.
| Configuration Parameter | Description |
|-------------------------|--------------------------------------------------------------------------------------|
| deviceNameInHub | Device name that identifies the Heatmiser device in the NeoHub and the Heatmiser App |
## Channels for "NeoHub"
The following Channels, and their associated channel types are shown below.
| Channel | Data Type | Description |
|----------------|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------|
| meshNetworkQoS | Number:Dimensionless | RF mesh network Quality-of-Service; this is the percentage of configured devices that are currently connected online via the RF mesh network |
## Channels for "NeoStat" Thermostat
The following Channels, and their associated channel types are shown below.
| Channel | Data Type | Description |
|-----------------------|--------------------|-----------------------------------------------------------------------------|
| roomTemperature | Number:Temperature | Actual room temperature |
| targetTemperature | Number:Temperature | Target temperature setting for the room |
| floorTemperature | Number:Temperature | Actual floor temperature |
| thermostatOutputState | String | Status of whether the thermostat is Off, or calling for Heat |
| occupancyModePresent | Switch | The thermostat is in the Present Occupancy Mode (Off=Absent, On=Present) |
| batteryLowAlarm | Switch | The battery is low (only applies for battery powered thermostats) (Off=Ok, On=Alarm) |
## Channels for "NeoPlug" Smart Plug
The following Channels, and their associated channel types are shown below.
| Channel | Data Type | Description |
|----------------------|-----------|----------------------------------------------------------|
| plugOutputState | Switch | The output state of the plug switch (Off, On) |
| plugAutoMode | Switch | The plug is in Automatic Mode (Off=Manual, On=Automatic) |
## Channels for "NeoContact" Contact Sensor
The following Channels, and their associated channel types are shown below.
| Channel | Data Type | Description |
|-------------------|-----------|----------------------------------------------------------|
| contactState | Contact | The state of the contact |
| batteryLowAlarm | Switch | The battery is low (Off=Ok, On=Alarm) |
## Channels for "NeoTemperatureSensor" Wireless Air Sensor
The following Channels, and their associated channel types are shown below.
| Channel | Data Type | Description |
|-------------------|--------------------|-------------------------------------------------|
| sensorTemperature | Number:Temperature | Actual measured temperature |
| batteryLowAlarm | Switch | The battery is low (Off=Ok, On=Alarm) |
## Channel Configuration (Optional)
The Heatmiser devices are connected to the NeoHub by means of an RF (radio frequency) mesh network.
Occasionally it is possible that a device might drop out of the mesh.
This is usually a temporary issue (e.g. interference), and the device usually reconnects itself automatically.
If a device drops out of the mesh, you can select whether openHAB shall either a) change the Channel value to `UNDEF`, or b) hold the value that it had prior to the drop out.
The choice of a) or b) is determined by an optional Channel configuration parameter `holdOnlineState` as follows.
| Parameter | Type | Description |
|-----------------|--------|-----------------------------------------------------------------------------------------------------|
| holdOnlineState | Switch | If the respective device drops out of the RF mesh, the behaviour is as follows:<br> - Off: openHAB changes the Channel's state to `UNDEF`<br> - On: openHAB holds the Channel's state unchanged<br>The default setting is Off |
The purpose of `holdOnlineState` is so you can choose to overlook value fluctuations if drop outs occur e.g. to "hold" the values in a temperature graph display.
Note: if a drop out occurs, the Thing will always change its status to `OFFLINE` (irrespective of the `holdOnlineState` setting).
## Full Example
### `demo.things` File
```
Bridge neohub:neohub:myhubname "Heatmiser NeoHub" [ hostName="192.168.1.123", portNumber=4242, pollingInterval=60, socketTimeout=5, preferLegacyApi=true ] {
Thing neoplug mydownstairs "Downstairs Plug" @ "Hall" [ deviceNameInHub="Hall Plug" ]
Thing neostat myupstairs "Upstairs Thermostat" @ "Landing" [ deviceNameInHub="Landing Thermostat" ]
Thing neocontact mycontact "Window Contact" @ "Bedroom" [ deviceNameInHub="Bedroom Window Contact" ]
Thing neotemperaturesensor mysensor "Kitchen Temperature" @ "Kitchen" [ deviceNameInHub="Kitchen Temperature Sensor" ]
}
```
### `demo.items` File
```
Number:Temperature Upstairs_RoomTemperature "Room Temperature" { channel="neohub:neostat:myhubname:myupstairs:roomTemperature" }
Number:Temperature Upstairs_TargetTemperature "Target Temperature" { channel="neohub:neostat:myhubname:myupstairs:targetTemperature" }
Number:Temperature Upstairs_FloorTemperature "Floor Temperature" { channel="neohub:neostat:myhubname:myupstairs:floorTemperature" }
String Upstairs_ThermostatOutputState "Heating State" { channel="neohub:neostat:myhubname:myupstairs:thermostatOutputState" }
Switch Upstairs_OccupancyModePresent "Occupancy Mode Present" { channel="neohub:neostat:myhubname:myupstairs:myupstairs:occupancyModePresent" }
Switch Downstairs_PlugAutoMode "Plug Auto Mode" { channel="neohub:neoplug:myhubname:mydownstairs:plugAutoMode" }
Switch Downstairs_PlugOutputState "Plug Output State" { channel="neohub:neoplug:myhubname:mydownstairs:plugOutputState" }
Contact Window_Contact_State "Window Contact State" { channel="neohub:neocontact:myhubname:mycontact:contactState" }
Switch Window_Contact_Battery_Low "Window Contact Battery Low" { channel="neohub:neocontact:myhubname:mycontact:batteryLowAlarm" }
Number:Temperature Kitchen_Temperature "Kitchen Temperature" { channel="neohub:neotemperaturesensor:myhubname:mysensor:sensorTemperature" }
```
### `demo.sitemap` File
```
sitemap neohub label="Heatmiser NeoHub"
{
Frame label="Thermostat" {
Text item=Upstairs_RoomTemperature
Setpoint item=Upstairs_TargetTemperature minValue=15 maxValue=30 step=1
Text item=Upstairs_ThermostatOutputState
Switch item=Upstairs_OccupancyModePresent
Text item=Upstairs_FloorTemperature
}
Frame label="Plug" {
Switch item=Downstairs_PlugOutputState
Switch item=Downstairs_PlugAutoMode
}
Frame label="Contact" {
Contact item=Window_Contact_State
Switch item=Window_Contact_Battery_Low
}
Frame label="Sensor" {
Text item=Kitchen_Temperature
}
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.neohub</artifactId>
<name>openHAB Add-ons :: Bundles :: NeoHub Binding</name>
</project>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.neohub-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-neohub" description="NeoHub Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.neohub/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link NeoBaseConfiguration} class contains the thing configuration
* parameters for NeoStat and NeoPlug devices
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class NeoBaseConfiguration {
public String deviceNameInHub = "";
}

View File

@@ -0,0 +1,286 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData.AbstractRecord;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.BridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link NeoBaseHandler} is the openHAB Handler for NeoPlug devices
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
public class NeoBaseHandler extends BaseThingHandler {
protected final Logger logger = LoggerFactory.getLogger(NeoBaseHandler.class);
protected @Nullable NeoBaseConfiguration config;
/*
* error messages
*/
private static final String MSG_FMT_DEVICE_CONFIG = "device \"{}\" needs to configured in hub!";
private static final String MSG_FMT_DEVICE_COMM = "device \"{}\" not communicating with hub!";
private static final String MSG_FMT_COMMAND_OK = "command for \"{}\" succeeded.";
private static final String MSG_FMT_COMMAND_BAD = "\"{}\" is an invalid or empty command!";
private static final String MSG_DEVICE_NAME_NOT_CONFIGURED = "the parameter \"deviceNameInHub\" is not configured";
/*
* an object used to de-bounce state changes between openHAB and the NeoHub
*/
protected NeoHubDebouncer debouncer = new NeoHubDebouncer();
public NeoBaseHandler(Thing thing) {
super(thing);
}
// ======== BaseThingHandler methods that are overridden =============
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
@Nullable
NeoHubHandler hub;
if ((hub = getNeoHub()) != null) {
if (command == RefreshType.REFRESH) {
hub.startFastPollingBurst();
return;
}
}
toNeoHubSendCommandSet(channelUID.getId(), command);
}
@Override
public void initialize() {
NeoBaseConfiguration config = getConfigAs(NeoBaseConfiguration.class);
if (config.deviceNameInHub.isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, MSG_DEVICE_NAME_NOT_CONFIGURED);
return;
}
this.config = config;
NeoHubHandler hub = getNeoHub();
if (hub == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, MSG_HUB_CONFIG);
return;
}
updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING);
}
// ======== helper methods used by this class or descendants ===========
/*
* this method is called back by the NeoHub handler to inform this handler about
* polling results from the hub handler
*/
public void toBaseSendPollResponse(NeoHubAbstractDeviceData deviceData) {
NeoBaseConfiguration config = this.config;
if (config == null) {
return;
}
AbstractRecord deviceRecord = deviceData.getDeviceRecord(config.deviceNameInHub);
if (deviceRecord == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
logger.warn(MSG_FMT_DEVICE_CONFIG, thing.getLabel());
return;
}
ThingStatus thingStatus = getThing().getStatus();
if (deviceRecord.offline() && (thingStatus == ThingStatus.ONLINE)) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
logger.debug(MSG_FMT_DEVICE_COMM, thing.getLabel());
return;
}
if ((!deviceRecord.offline()) && (thingStatus != ThingStatus.ONLINE)) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
}
toOpenHabSendChannelValues(deviceRecord);
}
/*
* internal method used by by sendChannelValuesToOpenHab(); it checks the
* de-bouncer before actually sending the channel value to openHAB; or if the
* device has lost its connection to the RF mesh, either a) send no updates to
* OpenHAB or b) send state = undefined, depending on the value of a
* Configuration Parameter
*/
protected void toOpenHabSendValueDebounced(String channelId, State state, boolean offline) {
/*
* if the device has been lost from the RF mesh network there are two possible
* behaviors: either a) do not report a state value, or b) show an undefined
* state; the choice of a) or b) depends on whether the channel has the
* Configuration Parameter holdOnlineState=true
*/
if (!offline) {
if (debouncer.timeExpired(channelId)) {
/*
* in normal circumstances just forward the hub's reported state to OpenHAB
*/
updateState(channelId, state);
}
} else {
ChannelUID channelUID = new ChannelUID(thing.getUID(), channelId);
Channel channel = thing.getChannel(channelUID);
if (channel != null) {
Configuration config = channel.getConfiguration();
Object holdOnlineState = config.get(PARAM_HOLD_ONLINE_STATE);
if (holdOnlineState != null && (holdOnlineState instanceof Boolean)
&& ((Boolean) holdOnlineState).booleanValue()) {
/*
* the Configuration Parameter "holdOnlineState" is True so do NOT send a
* state update to OpenHAB
*/
return;
}
}
/*
* the Configuration Parameter "holdOnlineState" is either not existing or
* it is False so send a state=undefined update to OpenHAB
*/
updateState(channelUID, UnDefType.UNDEF);
}
}
/*
* sends a channel command & value from openHAB => NeoHub. It delegates upwards
* to the NeoHub to handle the command
*/
protected void toNeoHubSendCommand(String channelId, Command command) {
String cmdStr = toNeoHubBuildCommandString(channelId, command);
if (!cmdStr.isEmpty()) {
NeoHubHandler hub = getNeoHub();
if (hub != null) {
/*
* issue command, check result, and update status accordingly
*/
switch (hub.toNeoHubSendChannelValue(cmdStr)) {
case SUCCEEDED:
logger.debug(MSG_FMT_COMMAND_OK, getThing().getLabel());
if (getThing().getStatus() != ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
}
// initialize the de-bouncer for this channel
debouncer.initialize(channelId);
break;
case ERR_COMMUNICATION:
logger.debug(MSG_HUB_COMM);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
break;
case ERR_INITIALIZATION:
logger.warn(MSG_HUB_CONFIG);
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
break;
}
} else {
logger.debug(MSG_HUB_CONFIG);
}
} else {
logger.debug(MSG_FMT_COMMAND_BAD, command.toString());
}
}
/**
* internal getter returns the NeoHub handler
*
* @return the neohub handler or null
*/
protected @Nullable NeoHubHandler getNeoHub() {
@Nullable
Bridge b;
@Nullable
BridgeHandler h;
if ((b = getBridge()) != null && (h = b.getHandler()) != null && h instanceof NeoHubHandler) {
return (NeoHubHandler) h;
}
return null;
}
// ========= methods that MAY / MUST be overridden in descendants ============
/*
* NOTE: descendant classes MUST override this method. It builds the command
* string to be sent to the NeoHub
*/
protected String toNeoHubBuildCommandString(String channelId, Command command) {
return "";
}
/*
* NOTE: descendant classes MAY override this method e.g. to send additional
* commands for dependent channels (if any)
*/
protected void toNeoHubSendCommandSet(String channelId, Command command) {
toNeoHubSendCommand(channelId, command);
}
/*
* NOTE: descendant classes MUST override this method method by which the
* handler informs openHAB about channel state changes
*/
protected void toOpenHabSendChannelValues(AbstractRecord deviceRecord) {
}
protected OnOffType invert(OnOffType value) {
return OnOffType.from(value == OnOffType.OFF);
}
protected Unit<?> getTemperatureUnit() {
@Nullable
NeoHubHandler hub = getNeoHub();
if (hub != null) {
return hub.getTemperatureUnit();
}
return SIUnits.CELSIUS;
}
}

View File

@@ -0,0 +1,49 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData.AbstractRecord;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.OpenClosedType;
import org.openhab.core.thing.Thing;
/**
* The {@link NeoContactHandler} is the OpenHAB Handler for NeoContact devices
*
* Note: inherits almost all the functionality of a {@link NeoBaseHandler}
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
public class NeoContactHandler extends NeoBaseHandler {
public NeoContactHandler(Thing thing) {
super(thing);
}
// =========== methods of NeoBaseHandler that are overridden ================
@Override
protected void toOpenHabSendChannelValues(AbstractRecord deviceRecord) {
boolean offline = deviceRecord.offline();
toOpenHabSendValueDebounced(CHAN_CONTACT_STATE,
deviceRecord.isWindowOpen() ? OpenClosedType.OPEN : OpenClosedType.CLOSED, offline);
toOpenHabSendValueDebounced(CHAN_BATTERY_LOW_ALARM, OnOffType.from(deviceRecord.isBatteryLow()), offline);
}
}

View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import java.math.BigDecimal;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* An abstract prototype for wrappers around JSON responses to JSON INFO or
* GET_LIVE_DATA requests
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public abstract class NeoHubAbstractDeviceData {
@SuppressWarnings("null")
@NonNullByDefault
public abstract static class AbstractRecord {
public abstract String getDeviceName();
public abstract BigDecimal getTargetTemperature();
public abstract BigDecimal getActualTemperature();
public abstract BigDecimal getFloorTemperature();
public abstract boolean isStandby();
public abstract boolean isHeating();
public abstract boolean isPreHeating();
public abstract boolean isTimerOn();
public abstract boolean offline();
public abstract boolean stateManual();
public abstract boolean stateAuto();
public abstract boolean isWindowOpen();
public abstract boolean isBatteryLow();
protected BigDecimal safeBigDecimal(@Nullable BigDecimal value) {
return value != null ? value : BigDecimal.ZERO;
}
}
/**
* returns the device record corresponding to a given device name
*
* @param deviceName the device name
* @return its respective device record
*/
public abstract @Nullable AbstractRecord getDeviceRecord(String deviceName);
/**
* @return the full list of device records
*/
public abstract @Nullable List<? extends AbstractRecord> getDevices();
}

View File

@@ -0,0 +1,191 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link NeoHubBindingConstants} class defines common constants
*
* @author Sebastian Prehn - Initial contribution (NeoHub command codes)
* @author Andrew Fiddian-Green - Initial contribution (OpenHAB v2.x binding
* code)
*
*/
@NonNullByDefault
public class NeoHubBindingConstants {
/*
* binding id
*/
public static final String BINDING_ID = "neohub";
/*
* device id's
*/
public static final String DEVICE_ID_NEOHUB = "neohub";
public static final String DEVICE_ID_NEOSTAT = "neostat";
public static final String DEVICE_ID_NEOPLUG = "neoplug";
public static final String DEVICE_ID_NEOCONTACT = "neocontact";
public static final String DEVICE_ID_NEOTEMPERATURESENSOR = "neotemperaturesensor";
/*
* Thing Type UIDs
*/
public static final ThingTypeUID THING_TYPE_NEOHUB = new ThingTypeUID(BINDING_ID, DEVICE_ID_NEOHUB);
public static final ThingTypeUID THING_TYPE_NEOSTAT = new ThingTypeUID(BINDING_ID, DEVICE_ID_NEOSTAT);
public static final ThingTypeUID THING_TYPE_NEOPLUG = new ThingTypeUID(BINDING_ID, DEVICE_ID_NEOPLUG);
public static final ThingTypeUID THING_TYPE_NEOCONTACT = new ThingTypeUID(BINDING_ID, DEVICE_ID_NEOCONTACT);
public static final ThingTypeUID THING_TYPE_NEOTEMPERATURESENSOR = new ThingTypeUID(BINDING_ID,
DEVICE_ID_NEOTEMPERATURESENSOR);
/*
* Channel IDs for NeoHub
*/
public static final String CHAN_MESH_NETWORK_QOS = "meshNetworkQoS";
/*
* Channel IDs common for several device types
*/
public static final String CHAN_BATTERY_LOW_ALARM = "batteryLowAlarm";
/*
* Channel IDs for NeoStat thermostats
*/
public static final String CHAN_ROOM_TEMP = "roomTemperature";
public static final String CHAN_TARGET_TEMP = "targetTemperature";
public static final String CHAN_FLOOR_TEMP = "floorTemperature";
public static final String CHAN_OCC_MODE_PRESENT = "occupancyModePresent";
public static final String CHAN_STAT_OUTPUT_STATE = "thermostatOutputState";
/*
* Channel IDs for NeoPlug smart plugs
*/
public static final String CHAN_PLUG_OUTPUT_STATE = "plugOutputState";
public static final String CHAN_PLUG_AUTO_MODE = "plugAutoMode";
/*
* Channel IDs for NeoContact (wireless) contact sensors
*/
public static final String CHAN_CONTACT_STATE = "contactState";
/*
* Channel IDs for NeoTemperatureSensor (wireless) temperature sensors
*/
public static final String CHAN_TEMPERATURE_SENSOR = "sensorTemperature";
/*
* Heatmiser Device Types
*/
public static final int HEATMISER_DEVICE_TYPE_CONTACT = 5;
public static final int HEATMISER_DEVICE_TYPE_PLUG = 6;
public static final int HEATMISER_DEVICE_TYPE_REPEATER = 10;
public static final int HEATMISER_DEVICE_TYPE_TEMPERATURE_SENSOR = 14;
/*
* configuration parameters
*/
public static final String PARAM_HOLD_ONLINE_STATE = "holdOnlineState";
/*
* regular expression pattern matchers
*/
public static final Pattern MATCHER_HEATMISER_REPEATER = Pattern.compile("^repeaternode\\d+");
public static final Pattern MATCHER_IP_ADDRESS = Pattern
.compile("\\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.|$)){4}\\b");
/*
* enumerator for results of method calls
*/
public static enum NeoHubReturnResult {
SUCCEEDED,
ERR_COMMUNICATION,
ERR_INITIALIZATION
}
/*
* the property IdD for the name of a thing in the NeoHub note: names may differ
* between the NeoHub and the OpenHAB framework
*/
public static final String DEVICE_NAME = "deviceNameInHub";
/*
* setup parameters for de-bouncing of state changes (time in seconds) so state
* changes that occur within this time window are ignored
*/
public static final long DEBOUNCE_DELAY = 15;
/*
* setup parameters for lazy polling
*/
public static final int LAZY_POLL_INTERVAL = 60;
/*
* setup parameters for fast polling bursts a burst comprises FAST_POLL_CYCLES
* polling calls spaced at FAST_POLL_INTERVAL for example 5 polling calls made
* at 4 second intervals (e.g. 5 x 4 => 20 seconds)
*/
public static final int FAST_POLL_CYCLES = 5;
public static final int FAST_POLL_INTERVAL = 4;
/*
* setup parameters for device discovery
*/
public static final int DISCOVERY_TIMEOUT = 5;
public static final int DISCOVERY_START_DELAY = 30;
public static final int DISCOVERY_REFRESH_PERIOD = 600;
/*
* NeoHub JSON command codes strings: Thanks to Sebastian Prehn !!
*/
public static final String CMD_CODE_INFO = "{\"INFO\":0}";
public static final String CMD_CODE_TEMP = "{\"SET_TEMP\":[%s, \"%s\"]}";
public static final String CMD_CODE_AWAY = "{\"FROST_%s\":\"%s\"}";
public static final String CMD_CODE_TIMER = "{\"TIMER_%s\":\"%s\"}";
public static final String CMD_CODE_MANUAL = "{\"MANUAL_%s\":\"%s\"}";
public static final String CMD_CODE_READ_DCB = "{\"READ_DCB\":100}";
/*
* note: from NeoHub rev2.6 onwards the INFO command is "deprecated" and it
* should be replaced partly each by the new GET_LIVE_DATA and GET_ENGINEERS
* commands
*/
public static final String CMD_CODE_GET_LIVE_DATA = "{\"GET_LIVE_DATA\":0}";
public static final String CMD_CODE_GET_ENGINEERS = "{\"GET_ENGINEERS\":0}";
/*
* note: from NeoHub rev2.6 onwards the READ_DCB command is "deprecated" and it
* should be replaced by the new GET_SYSTEM command
*/
public static final String CMD_CODE_GET_SYSTEM = "{\"GET_SYSTEM\":0}";
/*
* openHAB status strings
*/
public static final String VAL_OFF = "Off";
public static final String VAL_HEATING = "Heating";
/*
* logger message strings
*/
public static final String PLEASE_REPORT_BUG = "Unexpected situation - please report a bug: ";
public static final String MSG_HUB_CONFIG = PLEASE_REPORT_BUG + "hub needs to be initialized!";
public static final String MSG_HUB_COMM = PLEASE_REPORT_BUG + "error communicating with the hub!";
public static final String MSG_FMT_DEVICE_POLL_ERR = "Device data polling error: {}";
public static final String MSG_FMT_SYSTEM_POLL_ERR = "System data polling error: {}";
public static final String MSG_FMT_ENGINEERS_POLL_ERR = "Engineers data polling error: {}";
public static final String MSG_FMT_SET_VALUE_ERR = "{} set value error: {}";
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link NeoHubConfiguration} class contains the thing configuration
* parameters
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class NeoHubConfiguration {
public String hostName = "";
public int portNumber;
public int pollingInterval;
public int socketTimeout;
public boolean preferLegacyApi;
}

View File

@@ -0,0 +1,62 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.DEBOUNCE_DELAY;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link NeoHubDebouncer} determines if change events should be forwarded
* to a channel
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class NeoHubDebouncer {
private final Map<String, DebounceDelay> channels = new HashMap<>();
@SuppressWarnings("null")
@NonNullByDefault
static class DebounceDelay {
private long expireTime;
public DebounceDelay(Boolean enabled) {
if (enabled) {
expireTime = new Date().getTime() + (DEBOUNCE_DELAY * 1000);
}
}
public boolean timeExpired() {
return (expireTime < new Date().getTime());
}
}
public NeoHubDebouncer() {
}
public void initialize(String channelId) {
channels.put(channelId, new DebounceDelay(true));
}
@SuppressWarnings("null")
public boolean timeExpired(String channelId) {
return (channels.containsKey(channelId) ? channels.get(channelId).timeExpired() : true);
}
}

View File

@@ -0,0 +1,186 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData.AbstractRecord;
import org.openhab.binding.neohub.internal.NeoHubInfoResponse.InfoRecord;
import org.openhab.binding.neohub.internal.NeoHubLiveDeviceData.LiveDataRecord;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Discovery service for neo devices
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
public class NeoHubDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(NeoHubDiscoveryService.class);
private @Nullable ScheduledFuture<?> discoveryScheduler;
private NeoHubHandler hub;
public static final Set<ThingTypeUID> DISCOVERABLE_THING_TYPES_UIDS = Collections.unmodifiableSet(
Stream.of(THING_TYPE_NEOSTAT, THING_TYPE_NEOPLUG, THING_TYPE_NEOCONTACT, THING_TYPE_NEOTEMPERATURESENSOR)
.collect(Collectors.toSet()));
public NeoHubDiscoveryService(NeoHubHandler hub) {
// note: background discovery is enabled in the super method
super(DISCOVERABLE_THING_TYPES_UIDS, DISCOVERY_TIMEOUT);
this.hub = hub;
}
public void activate() {
super.activate(null);
}
@Override
public void deactivate() {
super.deactivate();
}
@Override
protected void startScan() {
if (hub.getThing().getStatus() == ThingStatus.ONLINE) {
discoverDevices();
}
}
@Override
protected void startBackgroundDiscovery() {
logger.debug("start background discovery..");
ScheduledFuture<?> discoveryScheduler = this.discoveryScheduler;
if (discoveryScheduler == null || discoveryScheduler.isCancelled()) {
this.discoveryScheduler = scheduler.scheduleWithFixedDelay(this::startScan, 10, DISCOVERY_REFRESH_PERIOD,
TimeUnit.SECONDS);
}
}
@Override
protected void stopBackgroundDiscovery() {
logger.debug("stop background discovery..");
ScheduledFuture<?> discoveryScheduler = this.discoveryScheduler;
if (discoveryScheduler != null && !discoveryScheduler.isCancelled()) {
discoveryScheduler.cancel(true);
}
}
private void discoverDevices() {
NeoHubAbstractDeviceData deviceData = hub.fromNeoHubGetDeviceData();
NeoHubGetEngineersData engineerData = hub.isLegacyApiSelected() ? null : hub.fromNeoHubGetEngineersData();
if (deviceData != null) {
List<? extends AbstractRecord> deviceRecords = deviceData.getDevices();
if (deviceRecords != null) {
int deviceType;
for (AbstractRecord deviceRecord : deviceRecords) {
// the record came from the legacy API (deviceType included)
if (deviceRecord instanceof InfoRecord) {
deviceType = ((InfoRecord) deviceRecord).getDeviceType();
publishDevice((InfoRecord) deviceRecord, deviceType);
continue;
}
// the record came from the now API (deviceType NOT included)
if (deviceRecord instanceof LiveDataRecord) {
if (engineerData == null) {
break;
}
String deviceName = ((LiveDataRecord) deviceRecord).getDeviceName();
// exclude repeater nodes from being discovered
if (MATCHER_HEATMISER_REPEATER.matcher(deviceName).matches()) {
continue;
}
deviceType = engineerData.getDeviceType(deviceName);
publishDevice((LiveDataRecord) deviceRecord, deviceType);
}
}
}
}
}
private void publishDevice(AbstractRecord device, int deviceId) {
if (deviceId <= 0) {
return;
}
String deviceType;
String deviceOpenHabId;
String deviceNeohubName;
ThingUID deviceUID;
ThingTypeUID deviceTypeUID;
DiscoveryResult discoveredDevice;
ThingUID bridgeUID = hub.getThing().getUID();
switch (deviceId) {
case HEATMISER_DEVICE_TYPE_CONTACT: {
deviceType = DEVICE_ID_NEOCONTACT;
deviceTypeUID = THING_TYPE_NEOCONTACT;
break;
}
case HEATMISER_DEVICE_TYPE_PLUG: {
deviceType = DEVICE_ID_NEOPLUG;
deviceTypeUID = THING_TYPE_NEOPLUG;
break;
}
case HEATMISER_DEVICE_TYPE_TEMPERATURE_SENSOR: {
deviceType = DEVICE_ID_NEOTEMPERATURESENSOR;
deviceTypeUID = THING_TYPE_NEOTEMPERATURESENSOR;
break;
}
// all other device types are assumed to be thermostats
default: {
deviceType = DEVICE_ID_NEOSTAT;
deviceTypeUID = THING_TYPE_NEOSTAT;
}
}
deviceNeohubName = device.getDeviceName();
deviceOpenHabId = deviceNeohubName.replaceAll("\\s+", "_");
deviceUID = new ThingUID(deviceTypeUID, bridgeUID, deviceOpenHabId);
discoveredDevice = DiscoveryResultBuilder.create(deviceUID).withBridge(bridgeUID).withLabel(deviceOpenHabId)
.withProperty(DEVICE_NAME, deviceNeohubName).withRepresentationProperty(DEVICE_NAME).build();
thingDiscovered(discoveredDevice);
logger.debug("discovered device: id={}, type={}, name={} ..", deviceId, deviceType, deviceOpenHabId);
}
}

View File

@@ -0,0 +1,31 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link NeoHubException} is a custom exception for NeoHub
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
public class NeoHubException extends Exception {
private static final long serialVersionUID = -7358712540781217363L;
public NeoHubException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,92 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import java.math.BigDecimal;
import java.util.HashMap;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.SerializedName;
/**
* A wrapper around the JSON response to the JSON GET_ENGINEERS request
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class NeoHubGetEngineersData {
private static final Gson GSON = new Gson();
@SuppressWarnings("null")
@NonNullByDefault
private static class EngineersRecords extends HashMap<String, EngineersRecord> {
private static final long serialVersionUID = 1L;
}
@SuppressWarnings("null")
@NonNullByDefault
public class EngineersRecord {
@SerializedName("DEVICE_TYPE")
private @Nullable BigDecimal deviceType;
public int getDeviceType() {
BigDecimal deviceType = this.deviceType;
return deviceType != null ? deviceType.intValue() : -1;
}
}
private @Nullable EngineersRecords deviceRecords;
/**
* Create wrapper around a JSON string
*
* @param fromJson the JSON string
* @return a NeoHubGetEngData wrapper around the JSON string
* @throws JsonSyntaxException
*
*/
public NeoHubGetEngineersData(String fromJson) throws JsonSyntaxException {
deviceRecords = GSON.fromJson(fromJson, EngineersRecords.class);
}
public static @Nullable NeoHubGetEngineersData createEngineersData(String fromJson) throws JsonSyntaxException {
return new NeoHubGetEngineersData(fromJson);
}
/**
* returns the device record corresponding to a given device name
*
* @param deviceName the device name
* @return its respective device information record
*/
private @Nullable EngineersRecord getDevice(String deviceName) {
EngineersRecords deviceRecords = this.deviceRecords;
return deviceRecords != null ? deviceRecords.get(deviceName) : null;
}
/**
* returns the deviceType corresponding to a given device name
*
* @param deviceName the device name
* @return its respective device information record
*/
public int getDeviceType(String deviceName) {
EngineersRecord record = getDevice(deviceName);
return record != null ? record.getDeviceType() : -1;
}
}

View File

@@ -0,0 +1,474 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
import java.io.IOException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData.AbstractRecord;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.unit.SIUnits;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.State;
import org.openhab.core.types.UnDefType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.JsonSyntaxException;
import tec.uom.se.unit.Units;
/**
* The {@link NeoHubHandler} is the openHAB Handler for NeoHub devices
*
* @author Andrew Fiddian-Green - Initial contribution (v2.x binding code)
* @author Sebastian Prehn - Initial contribution (v1.x hub communication)
*
*/
@NonNullByDefault
public class NeoHubHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(NeoHubHandler.class);
private final Map<String, Boolean> connectionStates = new HashMap<>();
private @Nullable NeoHubConfiguration config;
private @Nullable NeoHubSocket socket;
private @Nullable ScheduledFuture<?> lazyPollingScheduler;
private @Nullable ScheduledFuture<?> fastPollingScheduler;
private final AtomicInteger fastPollingCallsToGo = new AtomicInteger();
private @Nullable NeoHubReadDcbResponse systemData = null;
private boolean isLegacyApiSelected = true;
private boolean isApiOnline = false;
public NeoHubHandler(Bridge bridge) {
super(bridge);
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
// future: currently there is nothing to do for a NeoHub
}
@Override
public void initialize() {
NeoHubConfiguration config = getConfigAs(NeoHubConfiguration.class);
if (logger.isDebugEnabled()) {
logger.debug("hostname={}", config.hostName);
}
if (!MATCHER_IP_ADDRESS.matcher(config.hostName).matches()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "parameter hostName must be set!");
return;
}
if (logger.isDebugEnabled()) {
logger.debug("port={}", config.portNumber);
}
if (config.portNumber <= 0 || config.portNumber > 0xFFFF) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "portNumber is invalid!");
return;
}
if (logger.isDebugEnabled()) {
logger.debug("polling interval={}", config.pollingInterval);
}
if (config.pollingInterval < FAST_POLL_INTERVAL || config.pollingInterval > LAZY_POLL_INTERVAL) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, String
.format("pollingInterval must be in range [%d..%d]!", FAST_POLL_INTERVAL, LAZY_POLL_INTERVAL));
return;
}
if (logger.isDebugEnabled()) {
logger.debug("socketTimeout={}", config.socketTimeout);
}
if (config.socketTimeout < 5 || config.socketTimeout > 20) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
String.format("socketTimeout must be in range [%d..%d]!", 5, 20));
return;
}
if (logger.isDebugEnabled()) {
logger.debug("preferLegacyApi={}", config.preferLegacyApi);
}
socket = new NeoHubSocket(config.hostName, config.portNumber, config.socketTimeout);
this.config = config;
if (logger.isDebugEnabled()) {
logger.debug("start background polling..");
}
// create a "lazy" polling scheduler
ScheduledFuture<?> lazy = this.lazyPollingScheduler;
if (lazy == null || lazy.isCancelled()) {
this.lazyPollingScheduler = scheduler.scheduleWithFixedDelay(this::lazyPollingSchedulerExecute,
config.pollingInterval, config.pollingInterval, TimeUnit.SECONDS);
}
// create a "fast" polling scheduler
fastPollingCallsToGo.set(FAST_POLL_CYCLES);
ScheduledFuture<?> fast = this.fastPollingScheduler;
if (fast == null || fast.isCancelled()) {
this.fastPollingScheduler = scheduler.scheduleWithFixedDelay(this::fastPollingSchedulerExecute,
FAST_POLL_INTERVAL, FAST_POLL_INTERVAL, TimeUnit.SECONDS);
}
updateStatus(ThingStatus.UNKNOWN);
// start a fast polling burst to ensure the NeHub is initialized quickly
startFastPollingBurst();
}
@Override
public void dispose() {
if (logger.isDebugEnabled()) {
logger.debug("stop background polling..");
}
// clean up the lazy polling scheduler
ScheduledFuture<?> lazy = this.lazyPollingScheduler;
if (lazy != null && !lazy.isCancelled()) {
lazy.cancel(true);
this.lazyPollingScheduler = null;
}
// clean up the fast polling scheduler
ScheduledFuture<?> fast = this.fastPollingScheduler;
if (fast != null && !fast.isCancelled()) {
fast.cancel(true);
this.fastPollingScheduler = null;
}
}
/*
* device handlers call this to initiate a burst of fast polling requests (
* improves response time to users when openHAB changes a channel value )
*/
public void startFastPollingBurst() {
fastPollingCallsToGo.set(FAST_POLL_CYCLES);
}
/*
* device handlers call this method to issue commands to the NeoHub
*/
public synchronized NeoHubReturnResult toNeoHubSendChannelValue(String commandStr) {
NeoHubSocket socket = this.socket;
if (socket == null || config == null) {
return NeoHubReturnResult.ERR_INITIALIZATION;
}
try {
socket.sendMessage(commandStr);
// start a fast polling burst (to confirm the status change)
startFastPollingBurst();
return NeoHubReturnResult.SUCCEEDED;
} catch (Exception e) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
logger.warn(MSG_FMT_SET_VALUE_ERR, commandStr, e.getMessage());
return NeoHubReturnResult.ERR_COMMUNICATION;
}
}
/**
* sends a JSON request to the NeoHub to read the device data
*
* @return a class that contains the full status of all devices
*/
protected @Nullable NeoHubAbstractDeviceData fromNeoHubGetDeviceData() {
NeoHubSocket socket = this.socket;
if (socket == null || config == null) {
logger.warn(MSG_HUB_CONFIG);
return null;
}
try {
String responseJson;
NeoHubAbstractDeviceData deviceData;
if (isLegacyApiSelected) {
responseJson = socket.sendMessage(CMD_CODE_INFO);
deviceData = NeoHubInfoResponse.createDeviceData(responseJson);
} else {
responseJson = socket.sendMessage(CMD_CODE_GET_LIVE_DATA);
deviceData = NeoHubLiveDeviceData.createDeviceData(responseJson);
}
if (deviceData == null) {
logger.warn(MSG_FMT_DEVICE_POLL_ERR, "failed to create device data response");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
return null;
}
@Nullable
List<? extends AbstractRecord> devices = deviceData.getDevices();
if (devices == null || devices.size() == 0) {
logger.warn(MSG_FMT_DEVICE_POLL_ERR, "no devices found");
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
return null;
}
if (getThing().getStatus() != ThingStatus.ONLINE) {
updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
}
// check if we also need to discard and update systemData
NeoHubReadDcbResponse systemData = this.systemData;
if (systemData != null) {
if (deviceData instanceof NeoHubLiveDeviceData) {
/*
* note: time-stamps are measured in seconds from 1970-01-01T00:00:00Z
*
* new API: discard systemData if its time-stamp is older than the system
* time-stamp on the hub
*/
if (systemData.timeStamp < ((NeoHubLiveDeviceData) deviceData).getTimestampSystem()) {
this.systemData = null;
}
} else {
/*
* note: time-stamps are measured in seconds from 1970-01-01T00:00:00Z
*
* legacy API: discard systemData if its time-stamp is older than one hour
*/
if (systemData.timeStamp < Instant.now().minus(1, ChronoUnit.HOURS).getEpochSecond()) {
this.systemData = null;
}
}
}
return deviceData;
} catch (Exception e) {
logger.warn(MSG_FMT_DEVICE_POLL_ERR, e.getMessage());
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
return null;
}
}
/**
* sends a JSON request to the NeoHub to read the system data
*
* @return a class that contains the status of the system
*/
protected @Nullable NeoHubReadDcbResponse fromNeoHubReadSystemData() {
NeoHubSocket socket = this.socket;
if (socket == null) {
return null;
}
try {
String responseJson;
NeoHubReadDcbResponse systemData;
if (isLegacyApiSelected) {
responseJson = socket.sendMessage(CMD_CODE_READ_DCB);
systemData = NeoHubReadDcbResponse.createSystemData(responseJson);
} else {
responseJson = socket.sendMessage(CMD_CODE_GET_SYSTEM);
systemData = NeoHubReadDcbResponse.createSystemData(responseJson);
}
if (systemData == null) {
logger.warn(MSG_FMT_SYSTEM_POLL_ERR, "failed to create system data response");
return null;
}
return systemData;
} catch (Exception e) {
logger.warn(MSG_FMT_SYSTEM_POLL_ERR, e.getMessage());
return null;
}
}
/*
* this is the callback used by the lazy polling scheduler.. fetches the info
* for all devices from the NeoHub, and passes the results the respective device
* handlers
*/
private synchronized void lazyPollingSchedulerExecute() {
// check which API is supported
if (!isApiOnline) {
selectApi();
}
NeoHubAbstractDeviceData deviceData = fromNeoHubGetDeviceData();
if (deviceData != null) {
// dispatch deviceData to each of the hub's owned devices ..
List<Thing> children = getThing().getThings();
for (Thing child : children) {
ThingHandler device = child.getHandler();
if (device instanceof NeoBaseHandler) {
((NeoBaseHandler) device).toBaseSendPollResponse(deviceData);
}
}
// evaluate and update the state of our RF mesh QoS channel
List<? extends AbstractRecord> devices = deviceData.getDevices();
State state;
if (devices == null || devices.isEmpty()) {
state = UnDefType.UNDEF;
} else {
int totalDeviceCount = devices.size();
int onlineDeviceCount = 0;
for (AbstractRecord device : devices) {
String deviceName = device.getDeviceName();
Boolean online = !device.offline();
@Nullable
Boolean onlineBefore = connectionStates.put(deviceName, online);
if (!online.equals(onlineBefore)) {
logger.info("device \"{}\" has {} the RF mesh network", deviceName,
online.booleanValue() ? "joined" : "left");
}
if (online.booleanValue()) {
onlineDeviceCount++;
}
}
state = new QuantityType<>((100.0 * onlineDeviceCount) / totalDeviceCount, Units.PERCENT);
}
updateState(CHAN_MESH_NETWORK_QOS, state);
}
if (fastPollingCallsToGo.get() > 0) {
fastPollingCallsToGo.decrementAndGet();
}
}
/*
* this is the callback used by the fast polling scheduler.. checks if a fast
* polling burst is scheduled, and if so calls lazyPollingSchedulerExecute
*/
private void fastPollingSchedulerExecute() {
if (fastPollingCallsToGo.get() > 0) {
lazyPollingSchedulerExecute();
}
}
/*
* select whether to use the old "deprecated" API or the new API
*/
private void selectApi() {
boolean supportsLegacyApi = false;
boolean supportsFutureApi = false;
NeoHubSocket socket = this.socket;
if (socket != null) {
String responseJson;
NeoHubReadDcbResponse systemData;
try {
responseJson = socket.sendMessage(CMD_CODE_READ_DCB);
systemData = NeoHubReadDcbResponse.createSystemData(responseJson);
supportsLegacyApi = systemData != null;
if (!supportsLegacyApi) {
throw new NeoHubException("legacy API not supported");
}
} catch (JsonSyntaxException | NeoHubException | IOException e) {
// we learned that this API is not currently supported; no big deal
logger.debug("Legacy API is not supported!");
}
try {
responseJson = socket.sendMessage(CMD_CODE_GET_SYSTEM);
systemData = NeoHubReadDcbResponse.createSystemData(responseJson);
supportsFutureApi = systemData != null;
if (!supportsFutureApi) {
throw new NeoHubException("new API not supported");
}
} catch (JsonSyntaxException | NeoHubException | IOException e) {
// we learned that this API is not currently supported; no big deal
logger.debug("New API is not supported!");
}
}
if (!supportsLegacyApi && !supportsFutureApi) {
logger.warn("Currently neither legacy nor new API are supported!");
isApiOnline = false;
return;
}
NeoHubConfiguration config = this.config;
boolean isLegacyApiSelected = (supportsLegacyApi && config != null && config.preferLegacyApi);
if (isLegacyApiSelected != this.isLegacyApiSelected) {
logger.info("Changing API version: {}",
isLegacyApiSelected ? "\"new\" => \"legacy\"" : "\"legacy\" => \"new\"");
}
this.isLegacyApiSelected = isLegacyApiSelected;
this.isApiOnline = true;
}
/*
* get the Engineers data
*/
public @Nullable NeoHubGetEngineersData fromNeoHubGetEngineersData() {
NeoHubSocket socket = this.socket;
if (socket != null) {
String responseJson;
try {
responseJson = socket.sendMessage(CMD_CODE_GET_ENGINEERS);
return NeoHubGetEngineersData.createEngineersData(responseJson);
} catch (JsonSyntaxException | IOException | NeoHubException e) {
logger.warn(MSG_FMT_ENGINEERS_POLL_ERR, e.getMessage());
}
}
return null;
}
public boolean isLegacyApiSelected() {
return isLegacyApiSelected;
}
public Unit<?> getTemperatureUnit() {
NeoHubReadDcbResponse systemData = this.systemData;
if (systemData == null) {
this.systemData = systemData = fromNeoHubReadSystemData();
}
if (systemData != null) {
return systemData.getTemperatureUnit();
}
return SIUnits.CELSIUS;
}
}

View File

@@ -0,0 +1,137 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Component;
/**
* The {@link NeoHubHandlerFactory} creates things and thing handlers
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.neohub", service = ThingHandlerFactory.class)
public class NeoHubHandlerFactory extends BaseThingHandlerFactory {
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.unmodifiableSet(new HashSet<>(Arrays.asList(THING_TYPE_NEOHUB, THING_TYPE_NEOSTAT, THING_TYPE_NEOPLUG,
THING_TYPE_NEOCONTACT, THING_TYPE_NEOTEMPERATURESENSOR)));
private final Map<ThingUID, ServiceRegistration<?>> discoServices = new HashMap<>();
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if ((thingTypeUID.equals(THING_TYPE_NEOHUB)) && (thing instanceof Bridge)) {
NeoHubHandler handler = new NeoHubHandler((Bridge) thing);
createDiscoveryService(handler);
return handler;
}
if (thingTypeUID.equals(THING_TYPE_NEOSTAT)) {
return new NeoStatHandler(thing);
}
if (thingTypeUID.equals(THING_TYPE_NEOPLUG)) {
return new NeoPlugHandler(thing);
}
if (thingTypeUID.equals(THING_TYPE_NEOCONTACT)) {
return new NeoContactHandler(thing);
}
if (thingTypeUID.equals(THING_TYPE_NEOTEMPERATURESENSOR)) {
return new NeoTemperatureSensorHandler(thing);
}
return null;
}
@Override
protected synchronized void removeHandler(ThingHandler handler) {
if (handler instanceof NeoHubHandler) {
destroyDiscoveryService((NeoHubHandler) handler);
}
}
/*
* create a discovery service so that a newly created hub will find the
* respective things tht are inside it
*/
private synchronized void createDiscoveryService(NeoHubHandler handler) {
// create a new discovery service
NeoHubDiscoveryService ds = new NeoHubDiscoveryService(handler);
// activate the discovery service
ds.activate();
// register the discovery service
ServiceRegistration<?> serviceReg = bundleContext.registerService(DiscoveryService.class.getName(), ds,
new Hashtable<>());
/*
* store service registration in a list so we can destroy it when the respective
* hub is destroyed
*/
discoServices.put(handler.getThing().getUID(), serviceReg);
}
/*
* destroy the discovery service
*/
@SuppressWarnings("null")
private synchronized void destroyDiscoveryService(NeoHubHandler handler) {
// fetch the respective thing's service registration from our list
ServiceRegistration<?> serviceReg = discoServices.remove(handler.getThing().getUID());
if (serviceReg != null) {
// retrieve the respective discovery service
NeoHubDiscoveryService disco = (NeoHubDiscoveryService) bundleContext.getService(serviceReg.getReference());
// and unregister the service
serviceReg.unregister();
// deactivate the service
if (disco != null) {
disco.deactivate();
}
}
}
}

View File

@@ -0,0 +1,208 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import java.math.BigDecimal;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.SerializedName;
/**
* A wrapper around the JSON response to the JSON INFO request
*
* @author Sebastian Prehn - Initial contribution
* @author Andrew Fiddian-Green - Refactoring for openHAB v2.x
*
*/
@NonNullByDefault
public class NeoHubInfoResponse extends NeoHubAbstractDeviceData {
private static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(NeohubBool.class, new NeohubBoolDeserializer()).create();
@SerializedName("devices")
private @Nullable List<InfoRecord> deviceRecords;
@SuppressWarnings("null")
@NonNullByDefault
static class StatMode {
@SerializedName("MANUAL_OFF")
private @Nullable NeohubBool manualOff;
@SerializedName("MANUAL_ON")
private @Nullable NeohubBool manualOn;
private boolean stateManualOn() {
NeohubBool manualOn = this.manualOn;
return (manualOn == null ? false : manualOn.value);
}
private boolean stateManualOff() {
NeohubBool manualOff = this.manualOff;
return (manualOff == null ? false : manualOff.value);
}
}
@SuppressWarnings("null")
@NonNullByDefault
public static class InfoRecord extends AbstractRecord {
@SerializedName("device")
private @Nullable String deviceName;
@SerializedName("CURRENT_SET_TEMPERATURE")
private @Nullable BigDecimal currentSetTemperature;
@SerializedName("CURRENT_TEMPERATURE")
private @Nullable BigDecimal currentTemperature;
@SerializedName("CURRENT_FLOOR_TEMPERATURE")
private @Nullable BigDecimal currentFloorTemperature;
@SerializedName("COOL_INP")
private @Nullable NeohubBool coolInput;
@SerializedName("LOW_BATTERY")
private @Nullable NeohubBool batteryLow;
@SerializedName("STANDBY")
private @Nullable NeohubBool standby;
@SerializedName("HEATING")
private @Nullable NeohubBool heating;
@SerializedName("PREHEAT")
private @Nullable NeohubBool preHeat;
@SerializedName("TIMER")
private @Nullable NeohubBool timerOn;
@SerializedName("DEVICE_TYPE")
private @Nullable BigDecimal deviceType;
@SerializedName("OFFLINE")
private @Nullable NeohubBool offline;
@SerializedName("STAT_MODE")
private @Nullable StatMode statMode = new StatMode();
private boolean safeBoolean(@Nullable NeohubBool value) {
return (value == null ? false : value.value);
}
@Override
public String getDeviceName() {
String deviceName = this.deviceName;
return deviceName != null ? deviceName : "";
}
@Override
public BigDecimal getTargetTemperature() {
return safeBigDecimal(currentSetTemperature);
}
@Override
public BigDecimal getActualTemperature() {
return safeBigDecimal(currentTemperature);
}
@Override
public BigDecimal getFloorTemperature() {
return safeBigDecimal(currentFloorTemperature);
}
@Override
public boolean isStandby() {
return safeBoolean(standby);
}
@Override
public boolean isHeating() {
return safeBoolean(heating);
}
@Override
public boolean isPreHeating() {
return safeBoolean(preHeat);
}
@Override
public boolean isTimerOn() {
return safeBoolean(timerOn);
}
@Override
public boolean offline() {
return safeBoolean(offline);
}
@Override
public boolean stateManual() {
StatMode statMode = this.statMode;
return (statMode != null && statMode.stateManualOn());
}
@Override
public boolean stateAuto() {
StatMode statMode = this.statMode;
return (statMode != null && statMode.stateManualOff());
}
@Override
public boolean isWindowOpen() {
// legacy API misuses the cool input parameter
return safeBoolean(coolInput);
}
@Override
public boolean isBatteryLow() {
return safeBoolean(batteryLow);
}
public int getDeviceType() {
BigDecimal deviceType = this.deviceType;
return deviceType != null ? deviceType.intValue() : -1;
}
}
/**
* Create wrapper around a JSON string
*
* @param fromJson the JSON string
* @return a NeoHubInfoResponse wrapper around the JSON
* @throws JsonSyntaxException
*
*/
public static @Nullable NeoHubInfoResponse createDeviceData(String fromJson) throws JsonSyntaxException {
return GSON.fromJson(fromJson, NeoHubInfoResponse.class);
}
/**
* returns the device record corresponding to a given device name
*
* @param deviceName the device name
* @return its respective device record
*/
@Override
public @Nullable AbstractRecord getDeviceRecord(String deviceName) {
List<InfoRecord> deviceRecords = this.deviceRecords;
if (deviceRecords != null) {
for (AbstractRecord deviceRecord : deviceRecords) {
if (deviceName.equals(deviceRecord.getDeviceName())) {
return deviceRecord;
}
}
}
return null;
}
/**
* @return the full list of device records
*/
@Override
public @Nullable List<InfoRecord> getDevices() {
return deviceRecords;
}
}

View File

@@ -0,0 +1,194 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import java.math.BigDecimal;
import java.util.List;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.SerializedName;
/**
* A wrapper around the JSON response to the JSON GET_LIVE_DATA request
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class NeoHubLiveDeviceData extends NeoHubAbstractDeviceData {
private static final Gson GSON = new Gson();
@SerializedName("TIMESTAMP_ENGINEERS")
private @Nullable BigDecimal timestampEngineers;
@SerializedName("TIMESTAMP_SYSTEM")
private @Nullable BigDecimal timestampSystem;
@SerializedName("devices")
private @Nullable List<LiveDataRecord> deviceRecords;
@SuppressWarnings("null")
@NonNullByDefault
public static class LiveDataRecord extends AbstractRecord {
// "alternate" is a special kludge for technical devices
@SerializedName(value = "ZONE_NAME", alternate = { "device" })
private @Nullable String deviceName;
@SerializedName("SET_TEMP")
private @Nullable BigDecimal currentSetTemperature;
@SerializedName("ACTUAL_TEMP")
private @Nullable BigDecimal currentTemperature;
@SerializedName("CURRENT_FLOOR_TEMPERATURE")
private @Nullable BigDecimal currentFloorTemperature;
@SerializedName("WINDOW_OPEN")
private @Nullable Boolean windowOpen;
@SerializedName("LOW_BATTERY")
private @Nullable Boolean batteryLow;
@SerializedName("STANDBY")
private @Nullable Boolean standby;
@SerializedName("HEAT_ON")
private @Nullable Boolean heating;
@SerializedName("PREHEAT_ACTIVE")
private @Nullable Boolean preHeat;
@SerializedName("TIMER_ON")
private @Nullable Boolean timerOn;
@SerializedName("OFFLINE")
private @Nullable Boolean offline;
@SerializedName("MANUAL_OFF")
private @Nullable Boolean manualOff;
@SerializedName("MANUAL_ON")
private @Nullable Boolean manualOn;
private boolean safeBoolean(@Nullable Boolean value) {
return (value == null ? false : value.booleanValue());
}
@Override
public String getDeviceName() {
String deviceName = this.deviceName;
return deviceName != null ? deviceName : "";
}
@Override
public BigDecimal getTargetTemperature() {
return safeBigDecimal(currentSetTemperature);
}
@Override
public BigDecimal getActualTemperature() {
return safeBigDecimal(currentTemperature);
}
@Override
public BigDecimal getFloorTemperature() {
return safeBigDecimal(currentFloorTemperature);
}
@Override
public boolean isStandby() {
return safeBoolean(standby);
}
@Override
public boolean isHeating() {
return safeBoolean(heating);
}
@Override
public boolean isPreHeating() {
return safeBoolean(preHeat);
}
@Override
public boolean isTimerOn() {
return safeBoolean(timerOn);
}
@Override
public boolean offline() {
return safeBoolean(offline);
}
@Override
public boolean stateManual() {
return safeBoolean(manualOn);
}
@Override
public boolean stateAuto() {
return safeBoolean(manualOff);
}
@Override
public boolean isWindowOpen() {
return safeBoolean(windowOpen);
}
@Override
public boolean isBatteryLow() {
return safeBoolean(batteryLow);
}
}
public long getTimestampEngineers() {
BigDecimal timestampEngineers = this.timestampEngineers;
return timestampEngineers != null ? timestampEngineers.longValue() : 0;
}
public long getTimestampSystem() {
BigDecimal timestampSystem = this.timestampSystem;
return timestampSystem != null ? timestampSystem.longValue() : 0;
}
/**
* Create wrapper around a JSON string
*
* @param fromJson the JSON string
* @return a NeoHubGetLiveDataResponse wrapper around the JSON string
* @throws JsonSyntaxException
*
*/
public static @Nullable NeoHubLiveDeviceData createDeviceData(String fromJson) throws JsonSyntaxException {
return GSON.fromJson(fromJson, NeoHubLiveDeviceData.class);
}
/**
* returns the device record corresponding to a given device name
*
* @param deviceName the device name
* @return its respective device record
*/
@Override
public @Nullable AbstractRecord getDeviceRecord(String deviceName) {
List<LiveDataRecord> deviceRecords = this.deviceRecords;
if (deviceRecords != null) {
for (AbstractRecord deviceRecord : deviceRecords) {
if (deviceName.equals(deviceRecord.getDeviceName())) {
return deviceRecord;
}
}
}
return null;
}
/**
* @return the full list of device records
*/
@Override
public @Nullable List<LiveDataRecord> getDevices() {
return deviceRecords;
}
}

View File

@@ -0,0 +1,65 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import java.time.Instant;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.annotations.SerializedName;
/**
* A wrapper around the JSON response to the JSON READ_DCB and GET_SYSTEM
* request
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class NeoHubReadDcbResponse {
private static final Gson GSON = new Gson();
@SerializedName("CORF")
private @Nullable String degreesCorF;
/*
* note: time-stamps are measured in seconds from 1970-01-01T00:00:00Z
*
* this time-stamp is the moment of creation of this class instance; it is used
* to compare with the system last change time-stamp reported by the hub
*/
public final long timeStamp = Instant.now().getEpochSecond();
public Unit<?> getTemperatureUnit() {
return "F".equalsIgnoreCase(degreesCorF) ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS;
}
/**
* Create wrapper around a JSON string
*
* @param fromJson the JSON string
* @return a NeoHubReadDcbResponse wrapper around the JSON string
* @throws JsonSyntaxException
*
*/
public static @Nullable NeoHubReadDcbResponse createSystemData(String fromJson) throws JsonSyntaxException {
return GSON.fromJson(fromJson, NeoHubReadDcbResponse.class);
}
}

View File

@@ -0,0 +1,126 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static java.nio.charset.StandardCharsets.US_ASCII;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* NeoHubConnector handles the ASCII based communication via TCP between openHAB
* and NeoHub
*
* @author Sebastian Prehn - Initial contribution
* @author Andrew Fiddian-Green - Refactoring for openHAB v2.x
*
*/
@NonNullByDefault
public class NeoHubSocket {
private final Logger logger = LoggerFactory.getLogger(NeoHubSocket.class);
/**
* Name of host or IP to connect to.
*/
private final String hostname;
/**
* The port to connect to
*/
private final int port;
/**
* The socket connect resp. read timeout value
*/
private final int timeout;
public NeoHubSocket(final String hostname, final int portNumber, final int timeoutSeconds) {
this.hostname = hostname;
this.port = portNumber;
this.timeout = timeoutSeconds * 1000;
}
/**
* sends the message over the network to the NeoHub and returns its response
*
* @param requestJson the message to be sent to the NeoHub
* @return responseJson received from NeoHub
* @throws NeoHubException, IOException
*
*/
public String sendMessage(final String requestJson) throws IOException, NeoHubException {
IOException caughtException = null;
StringBuilder builder = new StringBuilder();
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(hostname, port), timeout);
socket.setSoTimeout(timeout);
try (InputStreamReader reader = new InputStreamReader(socket.getInputStream(), US_ASCII);
OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream(), US_ASCII)) {
if (logger.isDebugEnabled()) {
logger.debug("sending {} characters..", requestJson.length());
logger.debug(">> {}", requestJson);
}
writer.write(requestJson);
writer.write(0); // NULL terminate the command string
writer.flush();
if (logger.isTraceEnabled()) {
logger.trace("sent {} characters..", requestJson.length());
}
int inChar;
// NULL termination, end of stream (-1), or newline
while (((inChar = reader.read()) > 0) && (inChar != '\n')) {
builder.append((char) inChar);
}
}
} catch (IOException e) {
// catch IOExceptions here, and save them to be re-thrown later
caughtException = e;
}
String responseJson = builder.toString();
if (logger.isTraceEnabled()) {
logger.trace("received {} characters..", responseJson.length());
logger.trace("<< {}", responseJson);
} else
if (logger.isDebugEnabled()) {
logger.debug("received {} characters (set log level to TRACE to see full string)..", responseJson.length());
logger.debug("<< {} ...", responseJson.substring(0, Math.min(responseJson.length(), 30)));
}
// if any type of Exception was caught above, re-throw it again to the caller
if (caughtException != null) {
throw caughtException;
}
if (responseJson.isEmpty()) {
throw new NeoHubException("empty response string");
}
return responseJson;
}
}

View File

@@ -0,0 +1,68 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
/**
* The {@link NeoPlugHandler} is the OpenHAB Handler for NeoPlug devices Note:
* inherits almost all the functionality of a {@link NeoBaseHandler}
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
public class NeoPlugHandler extends NeoBaseHandler {
public NeoPlugHandler(Thing thing) {
super(thing);
}
// =========== methods of NeoBaseHandler that are overridden ================
@Override
protected String toNeoHubBuildCommandString(String channelId, Command command) {
NeoBaseConfiguration config = this.config;
if (config != null) {
if (command instanceof OnOffType && channelId.equals(CHAN_PLUG_OUTPUT_STATE)) {
return String.format(CMD_CODE_TIMER, ((OnOffType) command).toString(), config.deviceNameInHub);
}
if (command instanceof OnOffType && channelId.equals(CHAN_PLUG_AUTO_MODE)) {
return String.format(CMD_CODE_MANUAL, invert((OnOffType) command).toString(), config.deviceNameInHub);
}
}
return "";
}
@Override
protected void toNeoHubSendCommandSet(String channelId, Command command) {
// if this is a manual command, switch to manual mode first..
if (channelId.equals(CHAN_PLUG_OUTPUT_STATE) && command instanceof OnOffType) {
toNeoHubSendCommand(CHAN_PLUG_AUTO_MODE, OnOffType.from(false));
}
// send the actual command to the hub
toNeoHubSendCommand(channelId, command);
}
@Override
protected void toOpenHabSendChannelValues(NeoHubAbstractDeviceData.AbstractRecord deviceRecord) {
boolean offline = deviceRecord.offline();
toOpenHabSendValueDebounced(CHAN_PLUG_AUTO_MODE, OnOffType.from(!deviceRecord.stateManual()), offline);
toOpenHabSendValueDebounced(CHAN_PLUG_OUTPUT_STATE, OnOffType.from(deviceRecord.isTimerOn()), offline);
}
}

View File

@@ -0,0 +1,84 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
import javax.measure.Unit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
/**
* The {@link NeoStatHandler} is the openHAB Handler for NeoStat devices Note:
* inherits almost all the functionality of a {@link NeoBaseHandler}
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
public class NeoStatHandler extends NeoBaseHandler {
public NeoStatHandler(Thing thing) {
super(thing);
}
@Override
protected String toNeoHubBuildCommandString(String channelId, Command command) {
NeoBaseConfiguration config = this.config;
if (config != null) {
if (command instanceof QuantityType<?> && channelId.equals(CHAN_TARGET_TEMP)) {
Command doCommand = command;
QuantityType<?> temp = ((QuantityType<?>) command).toUnit(getTemperatureUnit());
if (temp != null) {
doCommand = temp;
}
return String.format(CMD_CODE_TEMP, ((QuantityType<?>) doCommand).toBigDecimal().toString(),
config.deviceNameInHub);
}
if (command instanceof OnOffType && channelId.equals(CHAN_OCC_MODE_PRESENT)) {
return String.format(CMD_CODE_AWAY, invert((OnOffType) command).toString(), config.deviceNameInHub);
}
}
return "";
}
@Override
protected void toOpenHabSendChannelValues(NeoHubAbstractDeviceData.AbstractRecord deviceRecord) {
Unit<?> unit = getTemperatureUnit();
boolean offline = deviceRecord.offline();
toOpenHabSendValueDebounced(CHAN_TARGET_TEMP, new QuantityType<>(deviceRecord.getTargetTemperature(), unit),
offline);
toOpenHabSendValueDebounced(CHAN_ROOM_TEMP, new QuantityType<>(deviceRecord.getActualTemperature(), unit),
offline);
toOpenHabSendValueDebounced(CHAN_FLOOR_TEMP, new QuantityType<>(deviceRecord.getFloorTemperature(), unit),
offline);
toOpenHabSendValueDebounced(CHAN_OCC_MODE_PRESENT, OnOffType.from(!deviceRecord.isStandby()), offline);
toOpenHabSendValueDebounced(CHAN_STAT_OUTPUT_STATE,
(deviceRecord.isHeating() || deviceRecord.isPreHeating() ? new StringType(VAL_HEATING)
: new StringType(VAL_OFF)),
offline);
toOpenHabSendValueDebounced(CHAN_BATTERY_LOW_ALARM, OnOffType.from(deviceRecord.isBatteryLow()), offline);
}
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.QuantityType;
import org.openhab.core.thing.Thing;
/**
* The {@link NeoTemperatureSensorHandler} is the OpenHAB Handler for NeoTemperatureSensor devices
*
* Note: inherits almost all the functionality of a {@link NeoBaseHandler}
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
public class NeoTemperatureSensorHandler extends NeoBaseHandler {
public NeoTemperatureSensorHandler(Thing thing) {
super(thing);
}
// =========== methods of NeoBaseHandler that are overridden ================
@Override
protected void toOpenHabSendChannelValues(NeoHubAbstractDeviceData.AbstractRecord deviceRecord) {
boolean offline = deviceRecord.offline();
toOpenHabSendValueDebounced(CHAN_TEMPERATURE_SENSOR,
new QuantityType<>(deviceRecord.getActualTemperature(), getTemperatureUnit()), offline);
toOpenHabSendValueDebounced(CHAN_BATTERY_LOW_ALARM, OnOffType.from(deviceRecord.isBatteryLow()), offline);
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* A custom class that wraps a boolean; we need this because newer versions of
* NeoHub have broken JSON for some boolean values so we can't use the standard
* deserializer, and thus have to use a custom one
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
public class NeohubBool {
public boolean value;
public NeohubBool(boolean value) {
this.value = value;
}
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) 2010-2020 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.neohub.internal;
import java.lang.reflect.Type;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
/**
* A custom deserializer for NeohubBool; we need this because newer versions of
* NeoHub have broken JSON for some boolean values so we can't use the standard
* deserializer, and thus have to use a custom one
*
* @author Andrew Fiddian-Green - Initial contribution
*
*/
@NonNullByDefault
public class NeohubBoolDeserializer implements JsonDeserializer<NeohubBool> {
@Override
public NeohubBool deserialize(@Nullable JsonElement json, @Nullable Type typeOfT,
@Nullable JsonDeserializationContext context) throws JsonParseException {
if (json != null) {
JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();
if (jsonPrimitive.isBoolean()) {
return new NeohubBool(jsonPrimitive.getAsBoolean());
} else if (jsonPrimitive.isNumber()) {
return new NeohubBool(jsonPrimitive.getAsNumber().intValue() != 0);
}
}
return new NeohubBool(false);
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="neohub" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>NeoHub Binding</name>
<description>This is the binding for Heatmiser NeoHub devices</description>
<author>Andrew Fiddian-Green</author>
</binding:binding>

View File

@@ -0,0 +1,310 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="neohub"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="neohub">
<label>NeoHub</label>
<description>Heatmiser NeoHub bridge to NeoStat and NeoPlug devices</description>
<channels>
<channel typeId="meshNetworkQoS" id="meshNetworkQoS"/>
</channels>
<properties>
<property name="vendor">Heatmiser</property>
<property name="modelId">NeoHub</property>
</properties>
<config-description>
<parameter name="hostName" type="text" required="true">
<label>Host Name</label>
<context>network-address</context>
<description>Host name (IP address) of the NeoHub</description>
</parameter>
<parameter name="portNumber" type="integer" required="false">
<label>Port Number</label>
<description>Port number of the NeoHub</description>
<default>4242</default>
<advanced>true</advanced>
</parameter>
<parameter name="pollingInterval" type="integer" min="4" max="60" required="false" unit="s">
<label>Polling Interval</label>
<description>Time (seconds) between polling the NeoHub (min=4, max/default=60)</description>
<default>60</default>
<advanced>true</advanced>
</parameter>
<parameter name="socketTimeout" type="integer" min="5" max="20" required="false" unit="s">
<label>Socket Timeout</label>
<description>Time (seconds) to wait for connections to the Hub (min/default=5, max=20)</description>
<default>5</default>
<advanced>true</advanced>
</parameter>
<parameter name="preferLegacyApi" type="boolean" required="false">
<label>Prefer Legacy API</label>
<description>Use the legacy API instead of the new API (if available)</description>
<default>false</default>
<advanced>true</advanced>
</parameter>
</config-description>
</bridge-type>
<thing-type id="neostat">
<supported-bridge-type-refs>
<bridge-type-ref id="neohub"/>
</supported-bridge-type-refs>
<label>Heatmiser NeoStat</label>
<description>Heatmiser Neo Smart Thermostat</description>
<channels>
<channel id="roomTemperature" typeId="temperature">
<label>Room Temperature</label>
<description>Actual room temperature</description>
</channel>
<channel id="targetTemperature" typeId="targetTemperature"/>
<channel id="floorTemperature" typeId="temperature">
<label>Floor Temperature</label>
<description>Actual floor temperature</description>
</channel>
<channel id="thermostatOutputState" typeId="thermostatOutputState"/>
<channel id="occupancyModePresent" typeId="occupancyModePresent"/>
<channel id="batteryLowAlarm" typeId="system.low-battery"/>
</channels>
<properties>
<property name="vendor">Heatmiser</property>
<property name="modelId">NeoStat</property>
</properties>
<representation-property>deviceNameInHub</representation-property>
<config-description>
<parameter name="deviceNameInHub" type="text" required="true">
<label>Device Name</label>
<description>Device Name that identifies the NeoStat device in the NeoHub and Heatmiser App</description>
</parameter>
</config-description>
</thing-type>
<thing-type id="neoplug">
<supported-bridge-type-refs>
<bridge-type-ref id="neohub"/>
</supported-bridge-type-refs>
<label>Heatmiser NeoPlug</label>
<description>Heatmiser Neo Smart Plug</description>
<channels>
<channel id="plugOutputState" typeId="plugOutputState"/>
<channel id="plugAutoMode" typeId="plugAutoMode"/>
</channels>
<properties>
<property name="vendor">Heatmiser</property>
<property name="modelId">NeoPlug</property>
</properties>
<representation-property>deviceNameInHub</representation-property>
<config-description>
<parameter name="deviceNameInHub" type="text" required="true">
<label>Device Name</label>
<description>Device Name that identifies the NeoPlug device in the NeoHub and Heatmiser App</description>
</parameter>
</config-description>
</thing-type>
<thing-type id="neocontact">
<supported-bridge-type-refs>
<bridge-type-ref id="neohub"/>
</supported-bridge-type-refs>
<label>Heatmiser Contact Sensor</label>
<description>Heatmiser (wireless) Window or Door Contact</description>
<channels>
<channel id="contactState" typeId="contactState"/>
<channel id="batteryLowAlarm" typeId="system.low-battery">
<label>Battery Low Alarm</label>
<description>ON if the device has a low battery</description>
</channel>
</channels>
<properties>
<property name="vendor">Heatmiser</property>
<property name="modelId">Contact Sensor</property>
</properties>
<representation-property>deviceNameInHub</representation-property>
<config-description>
<parameter name="deviceNameInHub" type="text" required="true">
<label>Device Name</label>
<description>Device Name that identifies the Contact in the NeoHub and Heatmiser App</description>
</parameter>
</config-description>
</thing-type>
<thing-type id="neotemperaturesensor">
<supported-bridge-type-refs>
<bridge-type-ref id="neohub"/>
</supported-bridge-type-refs>
<label>Heatmiser Wireless Air Sensor</label>
<description>Heatmiser (wireless) Temperature Sensor</description>
<channels>
<channel id="sensorTemperature" typeId="temperature">
<label>Temperature</label>
<description>Measured temperature value (Read-Only)</description>
</channel>
<channel id="batteryLowAlarm" typeId="system.low-battery">
<label>Battery Low Alarm</label>
<description>ON if the device has a low battery</description>
</channel>
</channels>
<properties>
<property name="vendor">Heatmiser</property>
<property name="modelId">Wireless Air Sensor</property>
</properties>
<representation-property>deviceNameInHub</representation-property>
<config-description>
<parameter name="deviceNameInHub" type="text" required="true">
<label>Device Name</label>
<description>Device Name that identifies the Temperature Sensor in the NeoHub and Heatmiser App</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="temperature">
<item-type>Number:Temperature</item-type>
<label>Temperature</label>
<description>Measured temperature value (Read-Only)</description>
<category>temperature</category>
<state readOnly="true" pattern="%.1f %unit%"/>
<config-description>
<parameter name="holdOnlineState" type="boolean" required="false">
<label>Hold Online State</label>
<description>If the device loses its RF mesh connection, hold the last known state display value</description>
<default>false</default>
</parameter>
</config-description>
</channel-type>
<channel-type id="targetTemperature">
<item-type>Number:Temperature</item-type>
<label>Target Temperature</label>
<description>Target temperature setting of the room</description>
<category>temperature</category>
<state readOnly="false" pattern="%.1f %unit%" step="1"/>
<config-description>
<parameter name="holdOnlineState" type="boolean" required="false">
<label>Hold Online State</label>
<description>If the device loses its RF mesh connection, hold the last known state display value</description>
<default>false</default>
</parameter>
</config-description>
</channel-type>
<channel-type id="thermostatOutputState">
<item-type>String</item-type>
<label>Thermostat Output State</label>
<description>Status of whether the thermostat is Off, or calling for Heat</description>
<category>fire</category>
<state readOnly="true"/>
<config-description>
<parameter name="holdOnlineState" type="boolean" required="false">
<label>Hold Online State</label>
<description>If the device loses its RF mesh connection, hold the last known state display value</description>
<default>false</default>
</parameter>
</config-description>
</channel-type>
<channel-type id="occupancyModePresent">
<item-type>Switch</item-type>
<label>Occupancy Mode Present</label>
<description>The Thermostat is in the Present Occupancy Mode (Off=Absent, On=Present)</description>
<category>presence</category>
<state readOnly="false"/>
<config-description>
<parameter name="holdOnlineState" type="boolean" required="false">
<label>Hold Online State</label>
<description>If the device loses its RF mesh connection, hold the last known state display value</description>
<default>false</default>
</parameter>
</config-description>
</channel-type>
<channel-type id="plugAutoMode">
<item-type>Switch</item-type>
<label>Plug Auto Mode</label>
<description>The Plug is in Automatic Mode (Off=Manual, On=Automatic)</description>
<category>energy</category>
<state readOnly="false"/>
<config-description>
<parameter name="holdOnlineState" type="boolean" required="false">
<label>Hold Online State</label>
<description>If the device loses its RF mesh connection, hold the last known state display value</description>
<default>false</default>
</parameter>
</config-description>
</channel-type>
<channel-type id="plugOutputState">
<item-type>Switch</item-type>
<label>Plug Output State</label>
<description>The state of the Plug switch, Off or On</description>
<state readOnly="false"/>
<config-description>
<parameter name="holdOnlineState" type="boolean" required="false">
<label>Hold Online State</label>
<description>If the device loses its RF mesh connection, hold the last known state display value</description>
<default>false</default>
</parameter>
</config-description>
</channel-type>
<channel-type id="contactState">
<item-type>Contact</item-type>
<label>Contact State</label>
<description>The state of the contact</description>
<category>window</category>
<state readOnly="true"/>
<config-description>
<parameter name="holdOnlineState" type="boolean" required="false">
<label>Hold Online State</label>
<description>If the device loses its RF mesh connection, hold the last known state display value</description>
<default>false</default>
</parameter>
</config-description>
</channel-type>
<channel-type id="meshNetworkQoS">
<item-type>Number:Dimensionless</item-type>
<label>Mesh Network QoS</label>
<description>Quality of Service: percentage of configured devices currently connected to the RF mesh network</description>
<state readOnly="true" pattern="%.0f %%"></state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,399 @@
/**
* Copyright (c) 2010-2020 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.neohub.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.openhab.binding.neohub.internal.NeoHubBindingConstants.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.Instant;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData;
import org.openhab.binding.neohub.internal.NeoHubAbstractDeviceData.AbstractRecord;
import org.openhab.binding.neohub.internal.NeoHubGetEngineersData;
import org.openhab.binding.neohub.internal.NeoHubInfoResponse;
import org.openhab.binding.neohub.internal.NeoHubInfoResponse.InfoRecord;
import org.openhab.binding.neohub.internal.NeoHubLiveDeviceData;
import org.openhab.binding.neohub.internal.NeoHubReadDcbResponse;
import org.openhab.binding.neohub.internal.NeoHubSocket;
import org.openhab.core.library.unit.ImperialUnits;
import org.openhab.core.library.unit.SIUnits;
/**
* The {@link NeoHubTestData} class defines common constants, which are used
* across the whole binding.
*
* @author Andrew Fiddian-Green - Initial contribution
*/
@NonNullByDefault
public class NeoHubTestData {
/*
* Load the test JSON payload string from a file
*/
private String load(String fileName) {
try (FileReader file = new FileReader(String.format("src/test/resources/%s.json", fileName));
BufferedReader reader = new BufferedReader(file)) {
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line).append("\n");
}
return builder.toString();
} catch (IOException e) {
fail(e.getMessage());
}
return "";
}
/*
* Test an INFO JSON response string as produced by older firmware versions
*/
@Test
public void testInfoJsonOld() {
// load INFO JSON response string in old JSON format
NeoHubAbstractDeviceData infoResponse = NeoHubInfoResponse.createDeviceData(load("info_old"));
assertNotNull(infoResponse);
// missing device
AbstractRecord device = infoResponse.getDeviceRecord("Aardvark");
assertNull(device);
// existing type 12 thermostat device
device = infoResponse.getDeviceRecord("Dining Room");
assertNotNull(device);
assertEquals("Dining Room", device.getDeviceName());
assertEquals(new BigDecimal("22.0"), device.getTargetTemperature());
assertEquals(new BigDecimal("22.2"), device.getActualTemperature());
assertEquals(new BigDecimal("23"), device.getFloorTemperature());
assertTrue(device instanceof InfoRecord);
assertEquals(12, ((InfoRecord) device).getDeviceType());
assertFalse(device.isStandby());
assertFalse(device.isHeating());
assertFalse(device.isPreHeating());
assertFalse(device.isTimerOn());
assertFalse(device.offline());
assertFalse(device.stateManual());
assertTrue(device.stateAuto());
assertFalse(device.isWindowOpen());
assertFalse(device.isBatteryLow());
// existing type 6 plug device (MANUAL OFF)
device = infoResponse.getDeviceRecord("Plug South");
assertNotNull(device);
assertEquals("Plug South", device.getDeviceName());
assertTrue(device instanceof InfoRecord);
assertEquals(6, ((InfoRecord) device).getDeviceType());
assertFalse(device.isTimerOn());
assertTrue(device.stateManual());
// existing type 6 plug device (MANUAL ON)
device = infoResponse.getDeviceRecord("Plug North");
assertNotNull(device);
assertEquals("Plug North", device.getDeviceName());
assertTrue(device instanceof InfoRecord);
assertEquals(6, ((InfoRecord) device).getDeviceType());
assertTrue(device.isTimerOn());
assertTrue(device.stateManual());
// existing type 6 plug device (AUTO OFF)
device = infoResponse.getDeviceRecord("Watering System");
assertNotNull(device);
assertEquals("Watering System", device.getDeviceName());
assertTrue(device instanceof InfoRecord);
assertEquals(6, ((InfoRecord) device).getDeviceType());
assertFalse(device.isTimerOn());
assertFalse(device.stateManual());
}
/*
* Test an INFO JSON response string as produced by newer firmware versions
*/
@Test
public void testInfoJsonNew() {
// load INFO JSON response string in new JSON format
NeoHubAbstractDeviceData infoResponse = NeoHubInfoResponse.createDeviceData(load("info_new"));
assertNotNull(infoResponse);
// existing device (new JSON format)
AbstractRecord device = infoResponse.getDeviceRecord("Dining Room");
assertNotNull(device);
assertEquals("Dining Room", device.getDeviceName());
assertFalse(device.offline());
assertFalse(device.isWindowOpen());
// existing repeater device
device = infoResponse.getDeviceRecord("repeaternode54473");
assertNotNull(device);
assertEquals("repeaternode54473", device.getDeviceName());
assertEquals(new BigDecimal("127"), device.getFloorTemperature());
assertEquals(new BigDecimal("255.255"), device.getActualTemperature());
}
/*
* Test for a READ_DCB JSON string that has valid CORF C response
*/
@Test
public void testReadDcbJson() {
// load READ_DCB JSON response string with valid CORF C response
NeoHubReadDcbResponse dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_celsius"));
assertNotNull(dcbResponse);
assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
// load READ_DCB JSON response string with valid CORF F response
dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_fahrenheit"));
assertNotNull(dcbResponse);
assertEquals(ImperialUnits.FAHRENHEIT, dcbResponse.getTemperatureUnit());
// load READ_DCB JSON response string with missing CORF element
dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_corf_missing"));
assertNotNull(dcbResponse);
assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
// load READ_DCB JSON response string where CORF element is an empty string
dcbResponse = NeoHubReadDcbResponse.createSystemData(load("dcb_corf_empty"));
assertNotNull(dcbResponse);
assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
}
/*
* Test an INFO JSON string that has a door contact and a temperature sensor
*/
@Test
public void testInfoJsonWithSensors() {
/*
* load an INFO JSON response string that has a closed door contact and a
* temperature sensor
*/
// save("info_sensors_closed", NEOHUB_JSON_TEST_STRING_INFO_SENSORS_CLOSED);
NeoHubAbstractDeviceData infoResponse = NeoHubInfoResponse.createDeviceData(load("info_sensors_closed"));
assertNotNull(infoResponse);
// existing contact device type 5 (CLOSED)
AbstractRecord device = infoResponse.getDeviceRecord("Back Door");
assertNotNull(device);
assertEquals("Back Door", device.getDeviceName());
assertTrue(device instanceof InfoRecord);
assertEquals(5, ((InfoRecord) device).getDeviceType());
assertFalse(device.isWindowOpen());
assertFalse(device.isBatteryLow());
// existing temperature sensor type 14
device = infoResponse.getDeviceRecord("Master Bedroom");
assertNotNull(device);
assertEquals("Master Bedroom", device.getDeviceName());
assertTrue(device instanceof InfoRecord);
assertEquals(14, ((InfoRecord) device).getDeviceType());
assertEquals(new BigDecimal("19.5"), device.getActualTemperature());
// existing thermostat type 1
device = infoResponse.getDeviceRecord("Living Room Floor");
assertNotNull(device);
assertEquals("Living Room Floor", device.getDeviceName());
assertTrue(device instanceof InfoRecord);
assertEquals(1, ((InfoRecord) device).getDeviceType());
assertEquals(new BigDecimal("19.8"), device.getActualTemperature());
// load an INFO JSON response string that has an open door contact
// save("info_sensors_open", NEOHUB_JSON_TEST_STRING_INFO_SENSORS_OPEN);
infoResponse = NeoHubInfoResponse.createDeviceData(load("info_sensors_open"));
assertNotNull(infoResponse);
// existing contact device type 5 (OPEN)
device = infoResponse.getDeviceRecord("Back Door");
assertNotNull(device);
assertEquals("Back Door", device.getDeviceName());
assertTrue(device instanceof InfoRecord);
assertEquals(5, ((InfoRecord) device).getDeviceType());
assertTrue(device.isWindowOpen());
assertTrue(device.isBatteryLow());
}
/*
* From NeoHub rev2.6 onwards the READ_DCB command is "deprecated" so we can
* also test the replacement GET_SYSTEM command (valid CORF response)
*/
@Test
public void testGetSystemJson() {
// load GET_SYSTEM JSON response string
NeoHubReadDcbResponse dcbResponse;
dcbResponse = NeoHubReadDcbResponse.createSystemData(load("system"));
assertNotNull(dcbResponse);
assertEquals(SIUnits.CELSIUS, dcbResponse.getTemperatureUnit());
}
/*
* From NeoHub rev2.6 onwards the INFO command is "deprecated" so we must test
* the replacement GET_LIVE_DATA command
*/
@Test
public void testGetLiveDataJson() {
// load GET_LIVE_DATA JSON response string
NeoHubLiveDeviceData liveDataResponse = NeoHubLiveDeviceData.createDeviceData(load("live_data"));
assertNotNull(liveDataResponse);
// test the time stamps
assertEquals(1588494785, liveDataResponse.getTimestampEngineers());
assertEquals(0, liveDataResponse.getTimestampSystem());
// missing device
AbstractRecord device = liveDataResponse.getDeviceRecord("Aardvark");
assertNull(device);
// test an existing thermostat device
device = liveDataResponse.getDeviceRecord("Dining Room");
assertNotNull(device);
assertEquals("Dining Room", device.getDeviceName());
assertEquals(new BigDecimal("22.0"), device.getTargetTemperature());
assertEquals(new BigDecimal("22.2"), device.getActualTemperature());
assertEquals(new BigDecimal("20.50"), device.getFloorTemperature());
assertFalse(device.isStandby());
assertFalse(device.isHeating());
assertFalse(device.isPreHeating());
assertFalse(device.isTimerOn());
assertFalse(device.offline());
assertFalse(device.stateManual());
assertTrue(device.stateAuto());
assertFalse(device.isWindowOpen());
assertFalse(device.isBatteryLow());
// test a plug device (MANUAL OFF)
device = liveDataResponse.getDeviceRecord("Living Room South");
assertNotNull(device);
assertEquals("Living Room South", device.getDeviceName());
assertFalse(device.isTimerOn());
assertTrue(device.stateManual());
// test a plug device (MANUAL ON)
device = liveDataResponse.getDeviceRecord("Living Room North");
assertNotNull(device);
assertEquals("Living Room North", device.getDeviceName());
assertTrue(device.isTimerOn());
assertTrue(device.stateManual());
// test a plug device (AUTO OFF)
device = liveDataResponse.getDeviceRecord("Green Wall Watering");
assertNotNull(device);
assertEquals("Green Wall Watering", device.getDeviceName());
assertFalse(device.isTimerOn());
assertFalse(device.stateManual());
// test a device that is offline
device = liveDataResponse.getDeviceRecord("Shower Room");
assertNotNull(device);
assertEquals("Shower Room", device.getDeviceName());
assertTrue(device.offline());
// test a device with a low battery
device = liveDataResponse.getDeviceRecord("Conservatory");
assertNotNull(device);
assertEquals("Conservatory", device.getDeviceName());
assertTrue(device.isBatteryLow());
// test a device with an open window alarm
device = liveDataResponse.getDeviceRecord("Door Contact");
assertNotNull(device);
assertEquals("Door Contact", device.getDeviceName());
assertTrue(device.isWindowOpen());
// test a wireless temperature sensor
device = liveDataResponse.getDeviceRecord("Room Sensor");
assertNotNull(device);
assertEquals("Room Sensor", device.getDeviceName());
assertEquals(new BigDecimal("21.5"), device.getActualTemperature());
// test a repeater node
device = liveDataResponse.getDeviceRecord("repeaternode54473");
assertNotNull(device);
assertEquals("repeaternode54473", device.getDeviceName());
assertTrue(MATCHER_HEATMISER_REPEATER.matcher(device.getDeviceName()).matches());
}
/*
* From NeoHub rev2.6 onwards the INFO command is "deprecated" and the DEVICE_ID
* element is not returned in the GET_LIVE_DATA call so we must test the
* replacement GET_ENGINEERS command
*/
@Test
public void testGetEngineersJson() {
// load GET_ENGINEERS JSON response string
NeoHubGetEngineersData engResponse = NeoHubGetEngineersData.createEngineersData(load("engineers"));
assertNotNull(engResponse);
// test device ID (type 12 thermostat device)
assertEquals(12, engResponse.getDeviceType("Dining Room"));
// test device ID (type 6 plug device)
assertEquals(6, engResponse.getDeviceType("Living Room South"));
}
/*
* send JSON request to the socket and retrieve JSON response
*/
private String testCommunicationInner(String requestJson) {
NeoHubSocket socket = new NeoHubSocket("192.168.1.109", 4242, 5);
String responseJson = "";
try {
responseJson = socket.sendMessage(requestJson);
} catch (Exception e) {
assertTrue(false);
}
return responseJson;
}
/*
* Test the communications
*/
@Test
public void testCommunications() {
String responseJson = testCommunicationInner(CMD_CODE_INFO);
assertFalse(responseJson.isEmpty());
responseJson = testCommunicationInner(CMD_CODE_READ_DCB);
assertFalse(responseJson.isEmpty());
NeoHubReadDcbResponse dcbResponse = NeoHubReadDcbResponse.createSystemData(responseJson);
assertNotNull(dcbResponse);
long timeStamp = dcbResponse.timeStamp;
assertEquals(Instant.now().getEpochSecond(), timeStamp, 1);
responseJson = testCommunicationInner(CMD_CODE_GET_LIVE_DATA);
assertFalse(responseJson.isEmpty());
NeoHubLiveDeviceData liveDataResponse = NeoHubLiveDeviceData.createDeviceData(responseJson);
assertNotNull(liveDataResponse);
assertTrue(timeStamp > liveDataResponse.getTimestampEngineers());
assertTrue(timeStamp > liveDataResponse.getTimestampSystem());
responseJson = testCommunicationInner(CMD_CODE_GET_ENGINEERS);
assertFalse(responseJson.isEmpty());
responseJson = testCommunicationInner(CMD_CODE_GET_SYSTEM);
assertFalse(responseJson.isEmpty());
responseJson = testCommunicationInner(String.format(CMD_CODE_TEMP, "20", "Hallway"));
assertFalse(responseJson.isEmpty());
}
}

View File

@@ -0,0 +1,45 @@
{
"AIR_ALT_DELAY": 60,
"AIR_ALT_DELAY_END": 6,
"AIR_ALT_DELAY_START": 23,
"ALT_TIMER_FORMAT": 1,
"AWAY": false,
"BOOTTIME": 1587842223,
"CLOSE_DELAY": null,
"COOLBOX": "heating",
"COOLBOX_PRESENT": 0,
"CORF": "C",
"DATE": "Apr 30",
"DEVICE_ID": "NeoHub",
"DSTAUTO": true,
"DSTON": true,
"EXTENDED_HISTORY": "off",
"Firmware version": 2134,
"GDEVLIST": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
],
"GLOBAL_SYSTEM_TYPE": "HeatOnly",
"HEATING_LEVELS": 4,
"HEATORCOOL": "HEAT",
"Homekit": true,
"LAST_RECONNECT": 191959,
"LAST_RECONNECT_TIME": 1588034182,
"NTP": "Running",
"OPEN_DELAY": null,
"PARTITION COUNT": "4",
"PROGFORMAT": 1,
"SET_GLOBAL_HC_MODE": "heating",
"TIME": "16:24:35",
"TIMEZONE": 0.0,
"UPTIME": 418052,
"ZIGBEE_CHANNEL": "15"
}

View File

@@ -0,0 +1,45 @@
{
"AIR_ALT_DELAY": 60,
"AIR_ALT_DELAY_END": 6,
"AIR_ALT_DELAY_START": 23,
"ALT_TIMER_FORMAT": 1,
"AWAY": false,
"BOOTTIME": 1587842223,
"CLOSE_DELAY": null,
"COOLBOX": "heating",
"COOLBOX_PRESENT": 0,
"CORF": "",
"DATE": "Apr 30",
"DEVICE_ID": "NeoHub",
"DSTAUTO": true,
"DSTON": true,
"EXTENDED_HISTORY": "off",
"Firmware version": 2134,
"GDEVLIST": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
],
"GLOBAL_SYSTEM_TYPE": "HeatOnly",
"HEATING_LEVELS": 4,
"HEATORCOOL": "HEAT",
"Homekit": true,
"LAST_RECONNECT": 191959,
"LAST_RECONNECT_TIME": 1588034182,
"NTP": "Running",
"OPEN_DELAY": null,
"PARTITION COUNT": "4",
"PROGFORMAT": 1,
"SET_GLOBAL_HC_MODE": "heating",
"TIME": "16:24:35",
"TIMEZONE": 0.0,
"UPTIME": 418052,
"ZIGBEE_CHANNEL": "15"
}

View File

@@ -0,0 +1,44 @@
{
"AIR_ALT_DELAY": 60,
"AIR_ALT_DELAY_END": 6,
"AIR_ALT_DELAY_START": 23,
"ALT_TIMER_FORMAT": 1,
"AWAY": false,
"BOOTTIME": 1587842223,
"CLOSE_DELAY": null,
"COOLBOX": "heating",
"COOLBOX_PRESENT": 0,
"DATE": "Apr 30",
"DEVICE_ID": "NeoHub",
"DSTAUTO": true,
"DSTON": true,
"EXTENDED_HISTORY": "off",
"Firmware version": 2134,
"GDEVLIST": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
],
"GLOBAL_SYSTEM_TYPE": "HeatOnly",
"HEATING_LEVELS": 4,
"HEATORCOOL": "HEAT",
"Homekit": true,
"LAST_RECONNECT": 191959,
"LAST_RECONNECT_TIME": 1588034182,
"NTP": "Running",
"OPEN_DELAY": null,
"PARTITION COUNT": "4",
"PROGFORMAT": 1,
"SET_GLOBAL_HC_MODE": "heating",
"TIME": "16:24:35",
"TIMEZONE": 0.0,
"UPTIME": 418052,
"ZIGBEE_CHANNEL": "15"
}

View File

@@ -0,0 +1,45 @@
{
"AIR_ALT_DELAY": 60,
"AIR_ALT_DELAY_END": 6,
"AIR_ALT_DELAY_START": 23,
"ALT_TIMER_FORMAT": 1,
"AWAY": false,
"BOOTTIME": 1587842223,
"CLOSE_DELAY": null,
"COOLBOX": "heating",
"COOLBOX_PRESENT": 0,
"CORF": "F",
"DATE": "Apr 30",
"DEVICE_ID": "NeoHub",
"DSTAUTO": true,
"DSTON": true,
"EXTENDED_HISTORY": "off",
"Firmware version": 2134,
"GDEVLIST": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
],
"GLOBAL_SYSTEM_TYPE": "HeatOnly",
"HEATING_LEVELS": 4,
"HEATORCOOL": "HEAT",
"Homekit": true,
"LAST_RECONNECT": 191959,
"LAST_RECONNECT_TIME": 1588034182,
"NTP": "Running",
"OPEN_DELAY": null,
"PARTITION COUNT": "4",
"PROGFORMAT": 1,
"SET_GLOBAL_HC_MODE": "heating",
"TIME": "16:24:35",
"TIMEZONE": 0.0,
"UPTIME": 418052,
"ZIGBEE_CHANNEL": "15"
}

View File

@@ -0,0 +1,211 @@
{
"Conservatory": {
"DEADBAND": 2,
"DEVICE_ID": 3,
"DEVICE_TYPE": 12,
"FLOOR_LIMIT": 38,
"FROST_TEMP": 12,
"MAX_PREHEAT": 2,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 24,
"SWITCHING DIFFERENTIAL": 1,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588493839,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
},
"Dining Room": {
"DEADBAND": 2,
"DEVICE_ID": 1,
"DEVICE_TYPE": 12,
"FLOOR_LIMIT": 37,
"FROST_TEMP": 12,
"MAX_PREHEAT": 2,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 24,
"SWITCHING DIFFERENTIAL": 1,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588493858,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
},
"Door Contact": {
"DEADBAND": 0,
"DEVICE_ID": 11,
"DEVICE_TYPE": 5,
"FLOOR_LIMIT": 0,
"FROST_TEMP": 0,
"MAX_PREHEAT": 0,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 0,
"SWITCHING DIFFERENTIAL": 0,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588700958,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": true
},
"Green Wall Watering": {
"DEADBAND": 0,
"DEVICE_ID": 10,
"DEVICE_TYPE": 6,
"FLOOR_LIMIT": 0,
"FROST_TEMP": 0,
"MAX_PREHEAT": 0,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 79,
"SWITCHING DIFFERENTIAL": 0,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588494897,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
},
"Hallway": {
"DEADBAND": 2,
"DEVICE_ID": 6,
"DEVICE_TYPE": 12,
"FLOOR_LIMIT": 37,
"FROST_TEMP": 12,
"MAX_PREHEAT": 2,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 24,
"SWITCHING DIFFERENTIAL": 1,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588493838,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
},
"Kitchen": {
"DEADBAND": 2,
"DEVICE_ID": 5,
"DEVICE_TYPE": 12,
"FLOOR_LIMIT": 37,
"FROST_TEMP": 12,
"MAX_PREHEAT": 2,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 24,
"SWITCHING DIFFERENTIAL": 1,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588493861,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
},
"Living Room": {
"DEADBAND": 2,
"DEVICE_ID": 4,
"DEVICE_TYPE": 12,
"FLOOR_LIMIT": 37,
"FROST_TEMP": 12,
"MAX_PREHEAT": 2,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 24,
"SWITCHING DIFFERENTIAL": 1,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588493838,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
},
"Living Room North": {
"DEADBAND": 0,
"DEVICE_ID": 9,
"DEVICE_TYPE": 6,
"FLOOR_LIMIT": 0,
"FROST_TEMP": 0,
"MAX_PREHEAT": 0,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 79,
"SWITCHING DIFFERENTIAL": 0,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588493846,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
},
"Living Room South": {
"DEADBAND": 0,
"DEVICE_ID": 8,
"DEVICE_TYPE": 6,
"FLOOR_LIMIT": 0,
"FROST_TEMP": 0,
"MAX_PREHEAT": 0,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 79,
"SWITCHING DIFFERENTIAL": 0,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588493846,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
},
"Shed Heating": {
"DEADBAND": 2,
"DEVICE_ID": 7,
"DEVICE_TYPE": 12,
"FLOOR_LIMIT": 28,
"FROST_TEMP": 9,
"MAX_PREHEAT": 0,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 24,
"SWITCHING DIFFERENTIAL": 1,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588493854,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
},
"Shower Room": {
"DEADBAND": 2,
"DEVICE_ID": 2,
"DEVICE_TYPE": 12,
"FLOOR_LIMIT": 28,
"FROST_TEMP": 12,
"MAX_PREHEAT": 2,
"OUTPUT_DELAY": 0,
"PUMP_DELAY": 0,
"RF_SENSOR_MODE": "self",
"STAT_FAILSAFE": 0,
"STAT_VERSION": 24,
"SWITCHING DIFFERENTIAL": 1,
"SWITCH_DELAY": 0,
"SYSTEM_TYPE": 0,
"TIMESTAMP": 1588493860,
"USER_LIMIT": 0,
"WINDOW_SWITCH_OPEN": false
}
}

View File

@@ -0,0 +1,730 @@
{
"devices": [
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 21,
"CURRENT_SET_TEMPERATURE": "22.0",
"CURRENT_TEMPERATURE": "24.0",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 21,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "24.0",
"MIN_TEMPERATURE": "21.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "3 days 23:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "3:24",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 24,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Dining Room"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "22.0",
"CURRENT_TEMPERATURE": "22.9",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 23,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "26.0",
"MIN_TEMPERATURE": "23.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "3 days 23:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "REMOTE_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 24,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Shower Room"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 23,
"CURRENT_SET_TEMPERATURE": "22.0",
"CURRENT_TEMPERATURE": "25.7",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 16,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "26.0",
"MIN_TEMPERATURE": "21.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "3 days 23:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 24,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Conservatory"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 27,
"CURRENT_SET_TEMPERATURE": "22.0",
"CURRENT_TEMPERATURE": "25.7",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 21,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "26.0",
"MIN_TEMPERATURE": "21.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "3 days 23:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "3:24",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 24,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Living Room"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 19,
"CURRENT_SET_TEMPERATURE": "21.0",
"CURRENT_TEMPERATURE": "23.0",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 21,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "24.0",
"MIN_TEMPERATURE": "20.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "3 days 23:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 24,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Kitchen"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 19,
"CURRENT_SET_TEMPERATURE": "20.0",
"CURRENT_TEMPERATURE": "21.7",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 21,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "23.0",
"MIN_TEMPERATURE": "21.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "3 days 22:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 24,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Hallway"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "9.0",
"CURRENT_TEMPERATURE": "19.4",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 9,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "22.0",
"MIN_TEMPERATURE": "15.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "4 days 08:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 5,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 24,
"WRITE_COUNT": 1,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Shed Heating"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "255.255",
"DEMAND": false,
"DEVICE_TYPE": 6,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 1,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "255.255",
"MIN_TEMPERATURE": "255.255",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "255 days 255:255",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_ON": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 79,
"WRITE_COUNT": 11,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Living Room South"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "255.255",
"DEMAND": false,
"DEVICE_TYPE": 6,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "255.255",
"MIN_TEMPERATURE": "255.255",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "255 days 255:255",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_ON": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": true,
"TIME_CLOCK_OVERIDE_BIT": true,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 79,
"WRITE_COUNT": 192,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Living Room North"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "255.255",
"DEMAND": false,
"DEVICE_TYPE": 6,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 1,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "255.255",
"MIN_TEMPERATURE": "255.255",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "255 days 255:255",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 79,
"WRITE_COUNT": 57,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Green Wall Watering"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "255.255",
"DEMAND": false,
"DEVICE_TYPE": 10,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "255.255",
"MIN_TEMPERATURE": "255.255",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "255 days 255:255",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "5DAY/2DAY",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 69,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "repeaternode54473"
}
]
}

View File

@@ -0,0 +1,664 @@
{
"devices": [
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 23,
"CURRENT_SET_TEMPERATURE": "22.0",
"CURRENT_TEMPERATURE": "22.2",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 21,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "22.0",
"MIN_TEMPERATURE": "21.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "6 days 23:00",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "2:42",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 20,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Dining Room"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "22.0",
"CURRENT_TEMPERATURE": "22.6",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 23,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "24.0",
"MIN_TEMPERATURE": "23.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "6 days 23:00",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "REMOTE_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 20,
"WRITE_COUNT": 4,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Shower Room"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 26,
"CURRENT_SET_TEMPERATURE": "22.0",
"CURRENT_TEMPERATURE": "23.3",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 16,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "25.0",
"MIN_TEMPERATURE": "20.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "6 days 23:00",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "3:48",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 20,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Conservatory"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 28,
"CURRENT_SET_TEMPERATURE": "22.0",
"CURRENT_TEMPERATURE": "22.6",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 21,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "24.0",
"MIN_TEMPERATURE": "19.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "6 days 23:00",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "3:16",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 20,
"WRITE_COUNT": 2,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Living Room"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 23,
"CURRENT_SET_TEMPERATURE": "22.0",
"CURRENT_TEMPERATURE": "23.6",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 21,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "23.0",
"MIN_TEMPERATURE": "20.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "6 days 23:00",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "2:08",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 20,
"WRITE_COUNT": 6,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Kitchen"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 17,
"CURRENT_SET_TEMPERATURE": "20.0",
"CURRENT_TEMPERATURE": "20.1",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 21,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "21.0",
"MIN_TEMPERATURE": "20.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "7 days 00:00",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AND_FLOOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 20,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Hallway"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 23,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "10.0",
"CURRENT_TEMPERATURE": "17.3",
"DEMAND": false,
"DEVICE_TYPE": 12,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 10,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "19.0",
"MIN_TEMPERATURE": "16.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "7 days 08:00",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 5,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 20,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Shed"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "255.255",
"DEMAND": false,
"DEVICE_TYPE": 6,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 1,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "255.255",
"MIN_TEMPERATURE": "255.255",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "255 days 255:255",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_ON": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 79,
"WRITE_COUNT": 11,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Plug South"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "255.255",
"DEMAND": false,
"DEVICE_TYPE": 6,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "255.255",
"MIN_TEMPERATURE": "255.255",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "255 days 255:255",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_ON": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": true,
"TIME_CLOCK_OVERIDE_BIT": true,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 79,
"WRITE_COUNT": 7,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Plug North"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 127,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "255.255",
"DEMAND": false,
"DEVICE_TYPE": 6,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 1,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "255.255",
"MIN_TEMPERATURE": "255.255",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "255 days 255:255",
"OFFLINE": false,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "24HOURSFIXED",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 79,
"WRITE_COUNT": 28,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Watering System"
}
]
}

View File

@@ -0,0 +1,466 @@
{
"devices": [
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 20,
"CURRENT_SET_TEMPERATURE": "20.0",
"CURRENT_TEMPERATURE": "19.8",
"DEMAND": false,
"DEVICE_TYPE": 1,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 12,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "20.0",
"MIN_TEMPERATURE": "19.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "5 days 19:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "5:13",
"PROGRAM_MODE": "5DAY/2DAY",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "FLOOR_SENSOR_ONLY",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 108,
"WRITE_COUNT": 89,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Living Room Floor"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 0,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "19.5",
"DEMAND": false,
"DEVICE_TYPE": 14,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "0.0",
"MIN_TEMPERATURE": "0.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "0 days 00:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "0:00",
"PROGRAM_MODE": "NONPROGRAMMABLE",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 0,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": false,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Master Bedroom"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 22,
"CURRENT_SET_TEMPERATURE": "12.0",
"CURRENT_TEMPERATURE": "21.5",
"DEMAND": false,
"DEVICE_TYPE": 1,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 12,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "1717",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "23.0",
"MIN_TEMPERATURE": "22.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "5 days 23:55",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "5DAY/2DAY",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "FLOOR_SENSOR_ONLY",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 108,
"WRITE_COUNT": 26,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Bathroom Floor"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 22,
"CURRENT_SET_TEMPERATURE": "12.0",
"CURRENT_TEMPERATURE": "21.6",
"DEMAND": false,
"DEVICE_TYPE": 1,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 24,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "23.0",
"MIN_TEMPERATURE": "21.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "5 days 22:30",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "1:02",
"PROGRAM_MODE": "5DAY/2DAY",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "FLOOR_SENSOR_ONLY",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 108,
"WRITE_COUNT": 27,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Ensuite Floor"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 0,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "20.0",
"DEMAND": false,
"DEVICE_TYPE": 14,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "0.0",
"MIN_TEMPERATURE": "0.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "0 days 00:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "0:00",
"PROGRAM_MODE": "NONPROGRAMMABLE",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 0,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": false,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Nursery"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 0,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "0.0",
"DEMAND": false,
"DEVICE_TYPE": 5,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "0.0",
"MIN_TEMPERATURE": "0.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "0 days 00:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "0:00",
"PROGRAM_MODE": "NONPROGRAMMABLE",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 0,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": false,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Back Door"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 0,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "0.0",
"DEMAND": false,
"DEVICE_TYPE": 5,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "0.0",
"MIN_TEMPERATURE": "0.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "0 days 00:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "0:00",
"PROGRAM_MODE": "NONPROGRAMMABLE",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 0,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": false,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Nursery Window"
}
]
}

View File

@@ -0,0 +1,466 @@
{
"devices": [
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 20,
"CURRENT_SET_TEMPERATURE": "7.0",
"CURRENT_TEMPERATURE": "19.8",
"DEMAND": false,
"DEVICE_TYPE": 1,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 12,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "20.0",
"MIN_TEMPERATURE": "19.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "255 days 255:255",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "5:13",
"PROGRAM_MODE": "5DAY/2DAY",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "FLOOR_SENSOR_ONLY",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": true,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 108,
"WRITE_COUNT": 90,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Living Room Floor"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 0,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "19.5",
"DEMAND": false,
"DEVICE_TYPE": 14,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "0.0",
"MIN_TEMPERATURE": "0.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "0 days 00:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "0:00",
"PROGRAM_MODE": "NONPROGRAMMABLE",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 0,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": false,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Master Bedroom"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 22,
"CURRENT_SET_TEMPERATURE": "12.0",
"CURRENT_TEMPERATURE": "21.6",
"DEMAND": false,
"DEVICE_TYPE": 1,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 12,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "1717",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "23.0",
"MIN_TEMPERATURE": "22.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "5 days 23:55",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "255:255",
"PROGRAM_MODE": "5DAY/2DAY",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "FLOOR_SENSOR_ONLY",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 108,
"WRITE_COUNT": 26,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Bathroom Floor"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 22,
"CURRENT_SET_TEMPERATURE": "12.0",
"CURRENT_TEMPERATURE": "21.6",
"DEMAND": false,
"DEVICE_TYPE": 1,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 24,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "23.0",
"MIN_TEMPERATURE": "21.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "5 days 22:30",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "1:02",
"PROGRAM_MODE": "5DAY/2DAY",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "FLOOR_SENSOR_ONLY",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 108,
"WRITE_COUNT": 27,
"ZONE_1PAIRED_TO_MULTILINK": true,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Ensuite Floor"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": false,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 0,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "20.0",
"DEMAND": false,
"DEVICE_TYPE": 14,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": false,
"MAX_TEMPERATURE": "0.0",
"MIN_TEMPERATURE": "0.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "0 days 00:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "0:00",
"PROGRAM_MODE": "NONPROGRAMMABLE",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"THERMOSTAT": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 0,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": false,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Nursery"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": true,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 0,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "0.0",
"DEMAND": false,
"DEVICE_TYPE": 5,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": true,
"MAX_TEMPERATURE": "0.0",
"MIN_TEMPERATURE": "0.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "0 days 00:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "0:00",
"PROGRAM_MODE": "NONPROGRAMMABLE",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 0,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": false,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Back Door"
},
{
"AWAY": false,
"COOLING": false,
"COOLING_ENABLED": false,
"COOLING_TEMPERATURE_IN_WHOLE_DEGREES": 0,
"COOL_INP": true,
"COUNT_DOWN_TIME": "0:00",
"CRADLE_PAIRED_TO_REMOTE_SENSOR": false,
"CRADLE_PAIRED_TO_STAT": false,
"CURRENT_FLOOR_TEMPERATURE": 0,
"CURRENT_SET_TEMPERATURE": "0.0",
"CURRENT_TEMPERATURE": "0.0",
"DEMAND": false,
"DEVICE_TYPE": 5,
"ENABLE_BOILER": false,
"ENABLE_COOLING": false,
"ENABLE_PUMP": false,
"ENABLE_VALVE": false,
"ENABLE_ZONE": false,
"FAILSAFE_STATE": false,
"FAIL_SAFE_ENABLED": false,
"FLOOR_LIMIT": false,
"FULL/PARTIAL_LOCK_AVAILABLE": false,
"HEAT/COOL_MODE": false,
"HEATING": false,
"HOLD_TEMPERATURE": 0,
"HOLD_TIME": "0:00",
"HOLIDAY": false,
"HOLIDAY_DAYS": 0,
"HUMIDITY": 0,
"LOCK": false,
"LOCK_PIN_NUMBER": "0000",
"LOW_BATTERY": true,
"MAX_TEMPERATURE": "0.0",
"MIN_TEMPERATURE": "0.0",
"MODULATION_LEVEL": 0,
"NEXT_ON_TIME": "0 days 00:00",
"OFFLINE": 0,
"OUPUT_DELAY": false,
"OUTPUT_DELAY": 0,
"PREHEAT": false,
"PREHEAT_TIME": "0:00",
"PROGRAM_MODE": "NONPROGRAMMABLE",
"PUMP_DELAY": false,
"RADIATORS_OR_UNDERFLOOR": false,
"SENSOR_SELECTION": "BUILT_IN_AIR_SENSOR",
"SET_COUNTDOWN_TIME": 0,
"STANDBY": false,
"STAT_MODE": {
"4_HEAT_LEVELS": true,
"MANUAL_OFF": true,
"TIMECLOCK": true
},
"TEMPERATURE_FORMAT": false,
"TEMP_HOLD": false,
"TIMECLOCK_MODE": false,
"TIMER": false,
"TIME_CLOCK_OVERIDE_BIT": false,
"ULTRA_VERSION": 0,
"VERSION_NUMBER": 0,
"WRITE_COUNT": 0,
"ZONE_1PAIRED_TO_MULTILINK": false,
"ZONE_1_OR_2": false,
"ZONE_2_PAIRED_TO_MULTILINK": false,
"device": "Nursery Window"
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
{
"ALT_TIMER_FORMAT": 1,
"CORF": "C",
"DEVICE_ID": "NeoHub",
"DST_AUTO": true,
"DST_ON": true,
"EXTENDED_HISTORY": "off",
"FORMAT": 1,
"GDEVLIST": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10
],
"GLOBAL_HC_MODE": "heating",
"GLOBAL_SYSTEM_TYPE": "HeatOnly",
"HEATING_LEVELS": 4,
"HUB_TYPE": 2,
"HUB_VERSION": 2134,
"NTP_ON": "Running",
"PARTITION": "4",
"TIMESTAMP": 0,
"TIMEZONESTR": null,
"TIME_ZONE": 0.0,
"UTC": 1588513535
}