Skip to content

Commit f332df7

Browse files
committed
GH-35: Control over Size & Precision in Thermostat Setpoint CC
- Precision has now its own attribute - Size is automatically determined based on value size Forwarded: #34 Bug-SiliconLabs: UIC-3320 Bug-Github: #34
1 parent 3b43b68 commit f332df7

File tree

5 files changed

+254
-49
lines changed

5 files changed

+254
-49
lines changed

applications/zpc/components/zpc_attribute_store/include/attribute_store_defined_attribute_types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,9 @@ DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE,
690690

691691
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE_SCALE,
692692
((COMMAND_CLASS_THERMOSTAT_SETPOINT << 8) | 0x09))
693+
694+
DEFINE_ATTRIBUTE(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE_PRECISION,
695+
((COMMAND_CLASS_THERMOSTAT_SETPOINT << 8) | 0x0A))
693696

694697
/////////////////////////////////////////////////
695698
// Wakeup command class

applications/zpc/components/zpc_attribute_store/src/zpc_attribute_store_type_registration.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ static const std::vector<attribute_schema_t> attribute_schema = {
298298
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, "Thermostat Setpoint Type", ATTRIBUTE_ENDPOINT_ID, I8_STORAGE_TYPE},
299299
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE, "Value", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, I32_STORAGE_TYPE},
300300
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE_SCALE, "Value Scale", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, U32_STORAGE_TYPE},
301+
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE_PRECISION, "Value Precision", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, U8_STORAGE_TYPE},
302+
301303
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MIN_VALUE, "Min Value", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, I32_STORAGE_TYPE},
302304
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MIN_VALUE_SCALE, "Min Value Scale", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, U32_STORAGE_TYPE},
303305
{ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_MAX_VALUE, "Max Value", ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_TYPE, I32_STORAGE_TYPE},

applications/zpc/components/zwave_command_classes/src/zwave_command_class_thermostat_setpoint.c

Lines changed: 90 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,14 @@ static attribute_store_node_t
229229
// Attribute resolution functions
230230
///////////////////////////////////////////////////////////////////////////////
231231
sl_status_t zwave_command_class_thermostat_setpoint_supported_get(
232-
attribute_store_node_t node, uint8_t *frame, uint16_t *frame_len)
232+
attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
233233
{
234234
// Check that we have the right type of attribute.
235235
assert(ATTRIBUTE(SUPPORTED_SETPOINT_TYPES)
236236
== attribute_store_get_node_type(node));
237237

238238
// Default frame length in case of error
239-
*frame_len = 0;
239+
*frame_length = 0;
240240

241241
// Supported Get is the same for all versions.
242242
ZW_THERMOSTAT_SETPOINT_SUPPORTED_GET_V3_FRAME *supported_get_frame
@@ -245,18 +245,18 @@ sl_status_t zwave_command_class_thermostat_setpoint_supported_get(
245245
supported_get_frame->cmdClass = COMMAND_CLASS_THERMOSTAT_SETPOINT_V3;
246246
supported_get_frame->cmd = THERMOSTAT_SETPOINT_SUPPORTED_GET_V3;
247247

248-
*frame_len = sizeof(ZW_THERMOSTAT_SETPOINT_SUPPORTED_GET_V3_FRAME);
248+
*frame_length = sizeof(ZW_THERMOSTAT_SETPOINT_SUPPORTED_GET_V3_FRAME);
249249
return SL_STATUS_OK;
250250
}
251251

252252
// FIXME: This will be failing CL:0043.01.21.02.1
253253
sl_status_t zwave_command_class_thermostat_setpoint_capabilities_get(
254-
attribute_store_node_t node, uint8_t *frame, uint16_t *frame_len)
254+
attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
255255
{
256256
// Check that we have the right type of attribute.
257257
assert(ATTRIBUTE(MIN_VALUE) == attribute_store_get_node_type(node));
258258
// Default frame length in case of error
259-
*frame_len = 0;
259+
*frame_length = 0;
260260

261261
attribute_store_node_t type_node = attribute_store_get_node_parent(node);
262262
attribute_store_node_t endpoint_node
@@ -297,20 +297,20 @@ sl_status_t zwave_command_class_thermostat_setpoint_capabilities_get(
297297
&capabilities_get_frame->properties1,
298298
sizeof(capabilities_get_frame->properties1));
299299

300-
*frame_len = sizeof(ZW_THERMOSTAT_SETPOINT_CAPABILITIES_GET_V3_FRAME);
300+
*frame_length = sizeof(ZW_THERMOSTAT_SETPOINT_CAPABILITIES_GET_V3_FRAME);
301301
return SL_STATUS_OK;
302302
}
303303
}
304304

305305
sl_status_t zwave_command_class_thermostat_setpoint_get(
306-
attribute_store_node_t node, uint8_t *frame, uint16_t *frame_len)
306+
attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
307307
{
308308
// Check that we have the right type of attribute.
309309
assert(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE
310310
== attribute_store_get_node_type(node));
311311

312312
// Default frame length in case of error
313-
*frame_len = 0;
313+
*frame_length = 0;
314314

315315
attribute_store_node_t type_node = attribute_store_get_node_parent(node);
316316

@@ -325,57 +325,94 @@ sl_status_t zwave_command_class_thermostat_setpoint_get(
325325
&get_frame->level,
326326
sizeof(get_frame->level));
327327

328-
*frame_len = sizeof(ZW_THERMOSTAT_SETPOINT_GET_V3_FRAME);
328+
*frame_length = sizeof(ZW_THERMOSTAT_SETPOINT_GET_V3_FRAME);
329329
return SL_STATUS_OK;
330330
}
331331

332332
sl_status_t zwave_command_class_thermostat_setpoint_set(
333-
attribute_store_node_t node, uint8_t *frame, uint16_t *frame_len)
333+
attribute_store_node_t node, uint8_t *frame, uint16_t *frame_length)
334334
{
335335
// Check that we have the right type of attribute.
336336
assert(ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE
337337
== attribute_store_get_node_type(node));
338338

339339
// Default frame length in case of error
340-
*frame_len = 0;
340+
*frame_length = 0;
341341

342-
attribute_store_node_t type_node = attribute_store_get_node_parent(node);
343-
attribute_store_node_t scale_node = attribute_store_get_first_child_by_type(
344-
type_node,
345-
ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE_SCALE);
346-
347-
// We will just always use 4 bytes, precision 2.
348-
ZW_THERMOSTAT_SETPOINT_SET_4BYTE_V3_FRAME *set_frame
349-
= (ZW_THERMOSTAT_SETPOINT_SET_4BYTE_V3_FRAME *)frame;
342+
attribute_store_node_t type_node = attribute_store_get_node_parent(node);
350343

351-
set_frame->cmdClass = COMMAND_CLASS_THERMOSTAT_SETPOINT_V3;
352-
set_frame->cmd = THERMOSTAT_SETPOINT_SET_V3;
353-
// set_frame->level ? This is 4 bits reserved / 4 bits setpoint type.
354-
set_frame->level = 0;
344+
// Get setpoint type
345+
uint8_t setpoint_type = 0;
355346
attribute_store_get_reported(type_node,
356-
&set_frame->level,
357-
sizeof(set_frame->level));
347+
&setpoint_type,
348+
sizeof(setpoint_type));
358349

359-
// set_frame->level2 ? This is Precision (3 bits) / Scale (2 bits) / size (3 bits)
360-
uint32_t setpoint_value_scale = 0;
361350
// Reuse the same scale as current value.
362-
attribute_store_get_reported(scale_node,
363-
&setpoint_value_scale,
364-
sizeof(setpoint_value_scale));
351+
uint32_t setpoint_value_scale = 0;
352+
attribute_store_get_child_reported(
353+
type_node,
354+
ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE_SCALE,
355+
&setpoint_value_scale,
356+
sizeof(setpoint_value_scale));
365357

366-
set_frame->level2 = SET_DEFAULT_PRECISION;
367-
set_frame->level2 |= SET_DEFAULT_SIZE;
368-
set_frame->level2 |= ((setpoint_value_scale << 3) & SCALE_MASK);
358+
// Reuse the same precision as current value.
359+
uint8_t setpoint_value_precision = 0;
360+
attribute_store_get_child_reported(
361+
type_node,
362+
ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE_PRECISION,
363+
&setpoint_value_precision,
364+
sizeof(setpoint_value_precision));
369365

366+
uint8_t level2_properties_field
367+
= (setpoint_value_precision << 5) | (setpoint_value_scale << 3);
370368
int32_t setpoint_value_integer
371369
= thermostat_setpoint_get_valid_desired_setpoint_value(node);
372370

373-
set_frame->value1 = (setpoint_value_integer & 0xFF000000) >> 24; // MSB
374-
set_frame->value2 = (setpoint_value_integer & 0x00FF0000) >> 16;
375-
set_frame->value3 = (setpoint_value_integer & 0x0000FF00) >> 8;
376-
set_frame->value4 = (setpoint_value_integer & 0x000000FF); // LSB
371+
if (setpoint_value_integer >= INT8_MIN
372+
&& setpoint_value_integer <= INT8_MAX) {
373+
ZW_THERMOSTAT_SETPOINT_SET_1BYTE_V3_FRAME *set_frame
374+
= (ZW_THERMOSTAT_SETPOINT_SET_1BYTE_V3_FRAME *)frame;
375+
*frame_length = sizeof(ZW_THERMOSTAT_SETPOINT_SET_1BYTE_V3_FRAME);
376+
377+
set_frame->cmdClass = COMMAND_CLASS_THERMOSTAT_SETPOINT_V3;
378+
set_frame->cmd = THERMOSTAT_SETPOINT_SET_V3;
379+
set_frame->level = setpoint_type;
380+
set_frame->level2 = level2_properties_field | 1;
381+
set_frame->value1 = (uint8_t)(setpoint_value_integer & 0x000000FF);
382+
} else if (setpoint_value_integer >= INT16_MIN
383+
&& setpoint_value_integer <= INT16_MAX) {
384+
ZW_THERMOSTAT_SETPOINT_SET_2BYTE_V3_FRAME *set_frame
385+
= (ZW_THERMOSTAT_SETPOINT_SET_2BYTE_V3_FRAME *)frame;
386+
*frame_length = sizeof(ZW_THERMOSTAT_SETPOINT_SET_2BYTE_V3_FRAME);
387+
388+
set_frame->cmdClass = COMMAND_CLASS_THERMOSTAT_SETPOINT_V3;
389+
set_frame->cmd = THERMOSTAT_SETPOINT_SET_V3;
390+
set_frame->level = setpoint_type;
391+
set_frame->level2 = level2_properties_field | 2;
392+
393+
set_frame->value1 = (setpoint_value_integer & 0x0000FF00) >> 8; // MSB
394+
set_frame->value2 = (setpoint_value_integer & 0x000000FF); // LSB
395+
396+
} else if (setpoint_value_integer >= INT32_MIN
397+
&& setpoint_value_integer <= INT32_MAX) {
398+
ZW_THERMOSTAT_SETPOINT_SET_4BYTE_V3_FRAME *set_frame
399+
= (ZW_THERMOSTAT_SETPOINT_SET_4BYTE_V3_FRAME *)frame;
400+
*frame_length = sizeof(ZW_THERMOSTAT_SETPOINT_SET_4BYTE_V3_FRAME);
401+
402+
set_frame->cmdClass = COMMAND_CLASS_THERMOSTAT_SETPOINT_V3;
403+
set_frame->cmd = THERMOSTAT_SETPOINT_SET_V3;
404+
set_frame->level = setpoint_type;
405+
set_frame->level2 = level2_properties_field | 4;
406+
407+
set_frame->value1 = (setpoint_value_integer & 0xFF000000) >> 24; // MSB
408+
set_frame->value2 = (setpoint_value_integer & 0x00FF0000) >> 16;
409+
set_frame->value3 = (setpoint_value_integer & 0x0000FF00) >> 8;
410+
set_frame->value4 = (setpoint_value_integer & 0x000000FF); // LSB
411+
} else {
412+
sl_log_error(LOG_TAG, "Invalid desired value size");
413+
return SL_STATUS_NOT_SUPPORTED;
414+
}
377415

378-
*frame_len = sizeof(ZW_THERMOSTAT_SETPOINT_SET_4BYTE_V3_FRAME);
379416
return SL_STATUS_OK;
380417
}
381418

@@ -389,7 +426,7 @@ static sl_status_t zwave_command_class_thermostat_setpoint_handle_report(
389426
{
390427
// We expect to have at least 1 byte of value
391428
if (frame_length <= REPORT_VALUE_INDEX) {
392-
return SL_STATUS_FAIL;
429+
return SL_STATUS_NOT_SUPPORTED;
393430
}
394431

395432
attribute_store_node_t endpoint_node
@@ -406,6 +443,12 @@ static sl_status_t zwave_command_class_thermostat_setpoint_handle_report(
406443
sizeof(uint8_t),
407444
0);
408445

446+
// Add guard in case we don't find it
447+
if (type_node == ATTRIBUTE_STORE_INVALID_NODE) {
448+
sl_log_warning(LOG_TAG, "Can't find setpoint type %d", received_type);
449+
return SL_STATUS_NOT_SUPPORTED;
450+
}
451+
409452
uint8_t size = frame_data[REPORT_PRECISION_SCALE_SIZE_INDEX] & SIZE_MASK;
410453
int32_t scale
411454
= (frame_data[REPORT_PRECISION_SCALE_SIZE_INDEX] & SCALE_MASK) >> 3;
@@ -419,9 +462,15 @@ static sl_status_t zwave_command_class_thermostat_setpoint_handle_report(
419462
attribute_store_node_t scale_node = attribute_store_get_first_child_by_type(
420463
type_node,
421464
ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE_SCALE);
422-
423465
attribute_store_set_reported(scale_node, &scale, sizeof(scale));
424466

467+
// Save precision
468+
attribute_store_set_child_reported(
469+
type_node,
470+
ATTRIBUTE_COMMAND_CLASS_THERMOSTAT_SETPOINT_VALUE_PRECISION,
471+
&precision,
472+
sizeof(precision));
473+
425474
int32_t setpoint_value
426475
= command_class_get_int32_value(size,
427476
precision,
@@ -688,9 +737,7 @@ sl_status_t zwave_command_class_thermostat_setpoint_init()
688737
handler.command_class_name = "Thermostat Setpoint";
689738
handler.comments = "Partial Control: <br>"
690739
"1. No discovery of ambiguous types in v1-v2 <br>"
691-
"2. Only a few setpoints can be configured. <br>"
692-
"3. Precision/size fields in the set are determined <br>"
693-
"automatically by the controller. ";
740+
"2. Only a few setpoints can be configured. <br>";
694741

695742
zwave_command_handler_register_handler(handler);
696743

applications/zpc/components/zwave_command_classes/src/zwave_command_class_thermostat_setpoint.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#define SCALE_MASK 0x18
3232
#define PRECISION_MASK 0xE0
3333

34-
#define SET_DEFAULT_PRECISION (3 << 5)
3534
#define SET_DEFAULT_SIZE 4
3635

3736
#define REPORT_SETPOINT_TYPE_INDEX 2

0 commit comments

Comments
 (0)