Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-32: Thermostat Mode CC correctly exposed to MQTT #32

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -15863,5 +15863,5 @@ export let ClusterTypeAttrs: any = {
commands: [
]
}
}
},
}
58 changes: 45 additions & 13 deletions applications/zpc/components/dotdot_mapper/rules/Thermostat.uam
Expand Up @@ -54,6 +54,10 @@ def zb_ACLouverPosition 0x02010045
def zb_ACCoilTemperature 0x02010046
def zb_ACCapacityFormat 0x02010047

// Unify thermostat cluster
def zb_ZWaveSystemMode 0xfd150001
def zb_SupportedSystemMode 0xfd150002

def thermostat_setpoint_supported (e'zwTHERMOSTAT_SETPOINT_TYPE[2].zwTHERMOSTAT_SETPOINT_VALUE_SCALE | e'zwTHERMOSTAT_SETPOINT_TYPE[1].zwTHERMOSTAT_SETPOINT_VALUE_SCALE)

scope 0 {
Expand Down Expand Up @@ -131,23 +135,48 @@ scope 0 {


r'zb_SystemMode =
if (r'zwTHERMOSTAT_MODE == 0) 0
if (r'zwTHERMOSTAT_MODE == 1) 4
if (r'zwTHERMOSTAT_MODE == 2) 3
if (r'zwTHERMOSTAT_MODE == 3) 1
if (r'zwTHERMOSTAT_MODE == 6) 7
if (r'zwTHERMOSTAT_MODE == 8) 8
if (r'zwTHERMOSTAT_MODE == 0x00) 0x00
if (r'zwTHERMOSTAT_MODE == 0x01) 0x04
if (r'zwTHERMOSTAT_MODE == 0x02) 0x03
if (r'zwTHERMOSTAT_MODE == 0x03) 0x01
if (r'zwTHERMOSTAT_MODE == 0x04) 0x0A
if (r'zwTHERMOSTAT_MODE == 0x05) 0x0B
if (r'zwTHERMOSTAT_MODE == 0x06) 0x07
if (r'zwTHERMOSTAT_MODE == 0x07) 0x0C
if (r'zwTHERMOSTAT_MODE == 0x08) 0x08
if (r'zwTHERMOSTAT_MODE == 0x09) 0x0D
if (r'zwTHERMOSTAT_MODE == 0x0A) 0x0E
if (r'zwTHERMOSTAT_MODE == 0x0B) 0x0F
if (r'zwTHERMOSTAT_MODE == 0x0C) 0x10
if (r'zwTHERMOSTAT_MODE == 0x0D) 0x11
if (r'zwTHERMOSTAT_MODE == 0x0F) 0x12
if (r'zwTHERMOSTAT_MODE == 0x1F) 0x13
undefined

d'zwTHERMOSTAT_MODE =
if ( d'zb_SystemMode == 0) 0
if ( d'zb_SystemMode == 4) 1
if ( d'zb_SystemMode == 3) 2
if ( d'zb_SystemMode == 1) 3
if ( d'zb_SystemMode == 7) 6
if ( d'zb_SystemMode == 8) 8
r'zwTHERMOSTAT_MODE =
if (r'zb_SystemMode == 0x00) 0x00
if (r'zb_SystemMode == 0x04) 0x01
if (r'zb_SystemMode == 0x03) 0x02
if (r'zb_SystemMode == 0x01) 0x03
if (r'zb_SystemMode == 0x0A) 0x04
if (r'zb_SystemMode == 0x0B) 0x05
if (r'zb_SystemMode == 0x07) 0x06
if (r'zb_SystemMode == 0x0C) 0x07
if (r'zb_SystemMode == 0x08) 0x08
if (r'zb_SystemMode == 0x0D) 0x09
if (r'zb_SystemMode == 0x0E) 0x0A
if (r'zb_SystemMode == 0x0F) 0x0B
if (r'zb_SystemMode == 0x10) 0x0C
if (r'zb_SystemMode == 0x11) 0x0D
if (r'zb_SystemMode == 0x12) 0x0F
if (r'zb_SystemMode == 0x13) 0x1F
undefined

// Unify cluster is 1on 1 mapping
r'zb_ZWaveSystemMode = r'zwTHERMOSTAT_MODE
r'zwTHERMOSTAT_MODE = r'zb_ZWaveSystemMode


r'zb_ControlSequenceOfOperation =
if(((r'zwTHERMOSTAT_SUPPORTED_MODES) & 6) == 0x06) 0x04
if(((r'zwTHERMOSTAT_SUPPORTED_MODES) & 6) == 0x02) 0x02
Expand Down Expand Up @@ -252,4 +281,7 @@ scope 0 chain_reaction(0) {
d'zb_ACCapacityFormat =
if (r'zb_ACCapacityFormat != d'zb_ACCapacityFormat) r'zb_ACCapacityFormat
undefined


r'zb_SupportedSystemMode = r'zwTHERMOSTAT_SUPPORTED_MODES
}
Expand Up @@ -289,7 +289,7 @@ static const std::vector<attribute_schema_t> attribute_schema = {
/////////////////////////////////////////////////////////////////////
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_MODE_VERSION, "Thermostat Mode Version", ATTRIBUTE_ENDPOINT_ID, U8_STORAGE_TYPE},
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_MODE, "Thermostat Mode", ATTRIBUTE_ENDPOINT_ID, I32_STORAGE_TYPE},
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SUPPORTED_MODES, "Thermostat Supported Modes", ATTRIBUTE_ENDPOINT_ID, BYTE_ARRAY_STORAGE_TYPE},
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SUPPORTED_MODES, "Thermostat Supported Modes", ATTRIBUTE_ENDPOINT_ID, U32_STORAGE_TYPE},
/////////////////////////////////////////////////////////////////////
// Thermostat Setpoint Command Class attributes
/////////////////////////////////////////////////////////////////////
Expand Down
Expand Up @@ -189,12 +189,23 @@ static sl_status_t zwave_command_class_thermostat_mode_handle_supported_report(

uint8_t bitmask_length
= frame_length - THERMOSTAT_MODE_SUPPORTED_REPORT_BITMASK_INDEX;
uint32_t supported_thermostat_bitmask = 0x0000;

attribute_store_set_node_attribute_value(
supported_modes_node,
REPORTED_ATTRIBUTE,
&frame_data[THERMOSTAT_MODE_SUPPORTED_REPORT_BITMASK_INDEX],
bitmask_length);
// Since we are using uint32_t we can't have more that 4 bit mask
if (bitmask_length > 4) {
sl_log_error(LOG_TAG,
"Supported Thermostat Mode type Bit Mask length is not supported\n");
return SL_STATUS_NOT_SUPPORTED;
}

for (int i = bitmask_length; i > 0; i--) {
supported_thermostat_bitmask
= (supported_thermostat_bitmask << 8) | frame_data[1 + i];
}

attribute_store_set_reported(supported_modes_node,
&supported_thermostat_bitmask,
sizeof(supported_thermostat_bitmask));

return SL_STATUS_OK;
}
Expand Down
Expand Up @@ -371,31 +371,29 @@ void test_thermostat_mode_incoming_supported_report_happy_case()
ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SUPPORTED_MODES,
endpoint_id_node);

uint8_t bit1 = 0b0000101;
uint8_t bit2 = 0b0000011;
uint8_t bit3 = 0b1111111;
const uint8_t incoming_report_frame[] = {COMMAND_CLASS_THERMOSTAT_MODE_V3,
THERMOSTAT_MODE_SUPPORTED_REPORT_V3,
1,
3,
4,
5,
6};
bit1,
bit2,
bit3};

TEST_ASSERT_EQUAL(
SL_STATUS_OK,
thermostat_mode_handler.control_handler(&connection_info,
incoming_report_frame,
sizeof(incoming_report_frame)));

uint8_t received_bitmask[20] = {};
uint8_t received_bitmask_length = 0;
attribute_store_get_node_attribute_value(supported_modes_node,
REPORTED_ATTRIBUTE,
received_bitmask,
&received_bitmask_length);

TEST_ASSERT_EQUAL(5, received_bitmask_length);
TEST_ASSERT_EQUAL_UINT8_ARRAY(&incoming_report_frame[2],
received_bitmask,
received_bitmask_length);
uint32_t received_bitmask = 0;
attribute_store_get_reported(supported_modes_node,
&received_bitmask,
sizeof(received_bitmask));

TEST_ASSERT_EQUAL_MESSAGE((bit3) << 16 | (bit2) << 8 | bit1,
received_bitmask,
"Received Bitmask mismatch");
}

void test_thermostat_mode_incoming_supported_report_too_short()
Expand Down
55 changes: 55 additions & 0 deletions components/uic_dotdot/dotdot-xml/Unify_Thermostat.xml
@@ -0,0 +1,55 @@
<?xml version="1.0"?>
<!--
Used to expose Protocol (ZWave) specific attributes to Unify.
-->
<zcl:cluster xmlns:zcl="http://zigbee.org/zcl/clusters"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:type="http://zigbee.org/zcl/types"
xmlns:xi="http://www.w3.org/2001/XInclude" xsi:schemaLocation="http://zigbee.org/zcl/clusters cluster.xsd http://zigbee.org/zcl/types type.xsd" id="FD15" revision="1" name="UnifyThermostat">
<classification role="application" picsCode="TSTAT" primaryTransaction="2" />
<server>
<attributes>
<attribute id="0001" name="ThermostatMode" type="enum8" writable="true" required="true" default="0">
<restriction>
<type:enumeration value="00" name="Off" />
<type:enumeration value="01" name="Heat" />
<type:enumeration value="02" name="Cool" />
<type:enumeration value="03" name="Auto" />
<type:enumeration value="04" name="Auxiliary" />
<type:enumeration value="05" name="Resume" />
<type:enumeration value="06" name="Fan" />
<type:enumeration value="07" name="Furnace" />
<type:enumeration value="08" name="Dry" />
<type:enumeration value="09" name="Moist" />
<type:enumeration value="0A" name="AutoChangeover" />
<type:enumeration value="0B" name="EnergyHeat" />
<type:enumeration value="0C" name="EnergyCool" />
<type:enumeration value="0D" name="Away" />
<!-- <type:enumeration value="0E" name="Reserved" /> -->
<type:enumeration value="0F" name="FullPower" />
<type:enumeration value="1F" name="ManufacturerSpecific" />
</restriction>
</attribute>
<attribute id="0002" name="SupportedThermostatMode" type="map16" writable="false" required="false" default="0">
<bitmap>
<element name="Off" type="bool" mask="01" />
<element name="Heat" type="bool" mask="02" shiftRight="1" />
<element name="Cool" type="bool" mask="04" shiftRight="2" />
<element name="Auto" type="bool" mask="08" shiftRight="3" />
<element name="Auxiliary" type="bool" mask="10" shiftRight="4" />
<element name="Resume" type="bool" mask="20" shiftRight="5" />
<element name="Fan" type="bool" mask="40" shiftRight="6" />
<element name="Furnace" type="bool" mask="80" shiftRight="7" />
<element name="Dry" type="bool" mask="100" shiftRight="8" />
<element name="Moist" type="bool" mask="200" shiftRight="9"/>
<element name="AutoChangeover" type="bool" mask="400" shiftRight="10"/>
<element name="EnergyHeat" type="bool" mask="800" shiftRight="10"/>
<element name="EnergyCool" type="bool" mask="1000" shiftRight="11"/>
<element name="Away" type="bool" mask="2000" shiftRight="12"/>
<element name="FullPower" type="bool" mask="4000" shiftRight="13"/>
<element name="ManufacturerSpecific" type="bool" mask="8000" shiftRight="14"/>
</bitmap>
</attribute>
</attributes>
</server>
</zcl:cluster>
2 changes: 1 addition & 1 deletion components/uic_dotdot/dotdot-xml/library.xml
Expand Up @@ -490,5 +490,5 @@ applicable to this document can be found in the LICENSE.md file.
<xi:include href="Unify_SystemMetrics.xml" parse="xml"/>
<xi:include href="Unify_ApplicationMonitoring.xml" parse="xml"/>
<xi:include href="Unify_Descriptor.xml" parse="xml"/>

<xi:include href="Unify_Thermostat.xml" parse="xml"/>
</zcl:library>
Expand Up @@ -856,6 +856,9 @@ typedef enum {
#define DOTDOT_PROTOCOL_CONTROLLER_NETWORK_MANAGEMENT_NETWORK_MANAGEMENT_STATE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x1)
// Definitions for cluster: Descriptor
#define DOTDOT_DESCRIPTOR_DEVICE_TYPE_LIST_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x0)
// Definitions for cluster: UnifyThermostat
#define DOTDOT_UNIFY_THERMOSTAT_THERMOSTAT_MODE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x1)
#define DOTDOT_UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_ATTRIBUTE_ID ((dotdot_attribute_id_t)0x2)

// clang-format on

Expand Down
Expand Up @@ -364,6 +364,8 @@

// Commands for cluster: Descriptor

// Commands for cluster: UnifyThermostat

#ifdef __cplusplus
extern "C" {
#endif
Expand Down
Expand Up @@ -254,6 +254,10 @@
#define DOTDOT_DESCRIPTOR_CLUSTER_ID ((dotdot_cluster_id_t)0xFD13)


// Definitions for cluster: UnifyThermostat
#define DOTDOT_UNIFY_THERMOSTAT_CLUSTER_ID ((dotdot_cluster_id_t)0xFD15)


#ifdef __cplusplus
extern "C" {
#endif
Expand Down
52 changes: 52 additions & 0 deletions components/uic_dotdot/zap-generated/include/zap-types.h
Expand Up @@ -1271,6 +1271,26 @@ typedef enum {
ZCL_TX_REPORT_TRANSMISSION_SPEED_UNKNOWN = 255,
} TxReportTransmissionSpeed;

// Enum for UnifyThermostatThermostatMode
typedef enum {
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_OFF = 0,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_HEAT = 1,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_COOL = 2,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_AUTO = 3,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_AUXILIARY = 4,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_RESUME = 5,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_FAN = 6,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_FURNACE = 7,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_DRY = 8,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_MOIST = 9,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_AUTO_CHANGEOVER = 10,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_ENERGY_HEAT = 11,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_ENERGY_COOL = 12,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_AWAY = 13,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_FULL_POWER = 15,
ZCL_UNIFY_THERMOSTAT_THERMOSTAT_MODE_MANUFACTURER_SPECIFIC = 31,
} UnifyThermostatThermostatMode;

// Enum for WindowCoveringWindowCoveringType
typedef enum {
ZCL_WINDOW_COVERING_WINDOW_COVERING_TYPE_ROLLERSHADE = 0,
Expand Down Expand Up @@ -1954,6 +1974,38 @@ typedef enum {
#define TSTAT_SCHEDULE_MODE_HEAT_OFFSET (0)
#define TSTAT_SCHEDULE_MODE_COOL (2)
#define TSTAT_SCHEDULE_MODE_COOL_OFFSET (1)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_OFF (1)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_OFF_OFFSET (0)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_HEAT (2)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_HEAT_OFFSET (1)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_COOL (4)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_COOL_OFFSET (2)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_AUTO (8)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_AUTO_OFFSET (3)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_AUXILIARY (16)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_AUXILIARY_OFFSET (4)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_RESUME (32)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_RESUME_OFFSET (5)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_FAN (64)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_FAN_OFFSET (6)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_FURNACE (128)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_FURNACE_OFFSET (7)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_DRY (256)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_DRY_OFFSET (8)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_MOIST (512)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_MOIST_OFFSET (9)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_AUTO_CHANGEOVER (1024)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_AUTO_CHANGEOVER_OFFSET (10)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_ENERGY_HEAT (2048)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_ENERGY_HEAT_OFFSET (11)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_ENERGY_COOL (4096)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_ENERGY_COOL_OFFSET (12)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_AWAY (8192)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_AWAY_OFFSET (13)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_FULL_POWER (16384)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_FULL_POWER_OFFSET (14)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_MANUFACTURER_SPECIFIC (32768)
#define UNIFY_THERMOSTAT_SUPPORTED_THERMOSTAT_MODE_MANUFACTURER_SPECIFIC_OFFSET (15)
#define WINDOW_COVERING_CONFIG_OR_STATUS_OPERATIONAL (1)
#define WINDOW_COVERING_CONFIG_OR_STATUS_OPERATIONAL_OFFSET (0)
#define WINDOW_COVERING_CONFIG_OR_STATUS_ONLINE (2)
Expand Down