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

Use interviewed setpoint byte size and precision in setpoint command #2458

Open
wants to merge 15 commits into
base: master
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/device_configuration.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
<xs:element name="ClassGetVersionSupported" type="xs:boolean" minOccurs='0'/>
<xs:element name="ForceUniqueEndpoints" type="xs:boolean" minOccurs='0'/>
<xs:element name="ForceUniqueEndpoints" type="xs:boolean" minOccurs='0'/>
<xs:element name="EnforceMinSizePrecision" type="xs:boolean" minOccurs='0'/>
<xs:element name="Base" type="xs:integer" minOccurs='0'/>
<xs:element name="OverridePrecision" type="xs:integer" minOccurs='0'/>
<xs:element name="ForceVersion" type="xs:integer" minOccurs='0'/>
Expand Down
4 changes: 3 additions & 1 deletion config/thermofloor/heatit058.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Product Revision="1" xmlns="https://github.com/OpenZWave/open-zwave">
<Product Revision="2" xmlns="https://github.com/OpenZWave/open-zwave">
<MetaData>
<MetaDataItem name="OzwInfoPage">http://www.openzwave.com/device-database/019B:0203:0003</MetaDataItem>
<MetaDataItem name="ProductPic">images/thermofloor/heatit058.png</MetaDataItem>
Expand Down Expand Up @@ -33,6 +33,7 @@ NB! Please use this procedure only when the primary controller/ gateway is missi
<MetaDataItem name="Name">Heatit Z-TRM3</MetaDataItem>
<ChangeLog>
<Entry author="Sebastian Hatzl - [email protected]" date="20 Aug 2020" revision="1">Initial Metadata Import from Z-Wave Alliance Database - https://products.z-wavealliance.org/products/3802/xml</Entry>
<Entry author="Cyberwizzard - [email protected]" date="12 Nov 2020" revision="2">Enabled EnforceMinSizePrecision compatibility flag to fix the setpoint command</Entry>
</ChangeLog>
</MetaData>
<CommandClass id="64">
Expand All @@ -57,6 +58,7 @@ NB! Please use this procedure only when the primary controller/ gateway is missi
<Instance index="1"/>
<Value genre="user" index="1" instance="1" label="Heating setpoint" max="0" min="0" units="C" read_only="false" type="decimal" value="21.0" write_only="false"/>
<Compatibility>
<EnforceMinSizePrecision>true</EnforceMinSizePrecision>
<Base>0</Base>
<CreateVars>true</CreateVars>
</Compatibility>
Expand Down
1 change: 1 addition & 0 deletions cpp/src/CompatOptionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace OpenZWave
{
{ "GetSupported", COMPAT_FLAG_GETSUPPORTED, COMPAT_FLAG_TYPE_BOOL },
{ "OverridePrecision", COMPAT_FLAG_OVERRIDEPRECISION, COMPAT_FLAG_TYPE_BYTE },
{ "EnforceMinSizePrecision", COMPAT_FLAG_ENFORCE_MINSIZEPRECISION, COMPAT_FLAG_TYPE_BOOL }, // HeatIt thermostats rely on setting the minimum byte size and minimum precision of the setpoint command via the capability report, set this to adopt this behavior
{ "ForceVersion", COMPAT_FLAG_FORCEVERSION, COMPAT_FLAG_TYPE_BYTE },
{ "CreateVars", COMPAT_FLAG_CREATEVARS, COMPAT_FLAG_TYPE_BOOL },
{ "RefreshOnWakeup", COMPAT_FLAG_REFRESHONWAKEUP, COMPAT_FLAG_TYPE_BOOL },
Expand Down
1 change: 1 addition & 0 deletions cpp/src/CompatOptionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ namespace OpenZWave
COMPAT_FLAG_NOT_ENABLECLEAR,
COMPAT_FLAG_NOT_V1ALARMTYPES_ENABLED,
COMPAT_FLAG_NO_REFRESH_AFTER_SET,
COMPAT_FLAG_ENFORCE_MINSIZEPRECISION,
STATE_FLAG_CCVERSION,
STATE_FLAG_STATIC_REQUESTS,
STATE_FLAG_AFTERMARK,
Expand Down
2 changes: 2 additions & 0 deletions cpp/src/ValueIDIndexesDefines.def
Original file line number Diff line number Diff line change
Expand Up @@ -3166,6 +3166,8 @@ ENUM(ValueID_Index_ThermostatSetpoint,
CoolingEcon,
AwayHeating,
CoolingHeating,
SetPointMinSize,
SetPointPrecision,
Unused_0_Minimum = 100,
Heating_Minimum,
Cooling_Minimum,
Expand Down
111 changes: 1 addition & 110 deletions cpp/src/ValueIDIndexesDefines.h

Large diffs are not rendered by default.

16 changes: 11 additions & 5 deletions cpp/src/command_classes/CommandClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -597,11 +597,11 @@ namespace OpenZWave
// <CommandClass::AppendValue>
// Add a value to a message as a sequence of bytes
//-----------------------------------------------------------------------------
void CommandClass::AppendValue(Msg* _msg, std::string const& _value, uint8 const _scale) const
void CommandClass::AppendValue(Msg* _msg, std::string const& _value, uint8 const _scale, uint8 const _minsize, uint8 const _minprecision) const
{
uint8 precision;
uint8 size;
int32 val = ValueToInteger(_value, &precision, &size);
int32 val = ValueToInteger(_value, &precision, &size, _minsize, _minprecision);

_msg->Append((precision << c_precisionShift) | (_scale << c_scaleShift) | size);

Expand All @@ -616,19 +616,20 @@ namespace OpenZWave
// <CommandClass::GetAppendValueSize>
// Get the number of bytes that would be added by a call to AppendValue
//-----------------------------------------------------------------------------
uint8 const CommandClass::GetAppendValueSize(std::string const& _value) const
uint8 const CommandClass::GetAppendValueSize(std::string const& _value, uint8 const _minsize, uint8 const _minprecision ) const
{
uint8 size;
ValueToInteger(_value, NULL, &size);
ValueToInteger(_value, NULL, &size, _minsize, _minprecision);
return size;
}

//-----------------------------------------------------------------------------
// <CommandClass::ValueToInteger>
// Convert a decimal string to an integer and report the precision and
// number of bytes required to store the value.
// If a minimum byte size or precisions is given, ensure the returned integer is using at least that precision and the reported o_size is at least _minsize
//-----------------------------------------------------------------------------
int32 CommandClass::ValueToInteger(std::string const& _value, uint8* o_precision, uint8* o_size) const
int32 CommandClass::ValueToInteger(std::string const& _value, uint8* o_precision, uint8* o_size, uint8 const _minsize, uint8 const _minprecision) const
{
int32 val;
uint8 precision;
Expand Down Expand Up @@ -656,6 +657,7 @@ namespace OpenZWave
}

uint8_t orp = m_com.GetFlagByte(COMPAT_FLAG_OVERRIDEPRECISION);
if (orp == 0 && _minprecision > 0) orp = _minprecision; // Only if no override is given and a valid _minprecision is used, force the precision to _minprecision
if (orp > 0)
{
while (precision < orp)
Expand Down Expand Up @@ -694,8 +696,12 @@ namespace OpenZWave
*o_size = 2;
}
}

if(*o_size < _minsize && (_minsize == 1 || _minsize == 2 || _minsize == 4))
*o_size = _minsize;
}


return val;
}

Expand Down
8 changes: 5 additions & 3 deletions cpp/src/command_classes/CommandClass.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,13 @@ namespace OpenZWave
* \param _msg The message to which the value should be appended.
* \param _value A string containing a decimal number to be appended.
* \param _scale A byte indicating the scale corresponding to this value (e.g., 1=F and 0=C for temperatures).
* \param _minsize Indicating the minimum size in bytes to pass the field value (default 0 to use the smallest size possible)
* \param _minprecision Indicating the minimum precision for the value, if the computed precision is lower it will be increased to this number of decimals and the raw value will be adjusted to match (default 0 to leave at computed value)
* \see Msg
*/
void AppendValue(Msg* _msg, string const& _value, uint8 const _scale) const;
uint8 const GetAppendValueSize(string const& _value) const;
int32 ValueToInteger(string const& _value, uint8* o_precision, uint8* o_size) const;
void AppendValue(Msg* _msg, string const& _value, uint8 const _scale, uint8 const _minsize = 0, uint8 const _minprecision = 0) const;
uint8 const GetAppendValueSize(string const& _value, uint8 const _minsize = 0, uint8 const _minprecision = 0) const;
int32 ValueToInteger(string const& _value, uint8* o_precision, uint8* o_size, uint8 const _minsize = 0, uint8 const _minprecision = 0) const;

void UpdateMappedClass(uint8 const _instance, uint8 const _classId, uint8 const _value); // Update mapped class's value from BASIC class

Expand Down
32 changes: 26 additions & 6 deletions cpp/src/command_classes/ThermostatSetpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "platform/Log.h"

#include "value_classes/ValueDecimal.h"
#include "value_classes/ValueByte.h"

#include "tinyxml.h"

Expand Down Expand Up @@ -69,6 +70,7 @@ namespace OpenZWave
{
m_com.EnableFlag(COMPAT_FLAG_TSSP_BASE, 1);
m_com.EnableFlag(COMPAT_FLAG_TSSP_ALTTYPEINTERPRETATION, true);
m_com.EnableFlag(COMPAT_FLAG_ENFORCE_MINSIZEPRECISION, false);
SetStaticRequest(StaticRequest_Values);
}

Expand Down Expand Up @@ -236,19 +238,26 @@ namespace OpenZWave
{
// We have received the capabilities for supported setpoint Type
uint8 scale;
uint8 precision = 0;
uint8 min_precision = 0;
uint8 max_precision = 0;
uint8 size = _data[2] & 0x07;
string minValue = ExtractValue(&_data[2], &scale, &precision);
string maxValue = ExtractValue(&_data[2 + size + 1], &scale, &precision);
string minValue = ExtractValue(&_data[2], &scale, &min_precision);
string maxValue = ExtractValue(&_data[2 + size + 1], &scale, &max_precision);

Log::Write(LogLevel_Info, GetNodeId(), "Received capabilities of thermostat setpoint type %d, min %s max %s", (int) _data[1], minValue.c_str(), maxValue.c_str());
Log::Write(LogLevel_Info, GetNodeId(), "Received capabilities of thermostat setpoint type %d, min %s (field size: %i bytes, precision: %i decimals) max %s (precision: %i decimals)", (int) _data[1], minValue.c_str(), size, min_precision, maxValue.c_str(), max_precision);

uint8 index = _data[1];
// Add supported setpoint
if (index < ThermostatSetpoint_Count)
{
string setpointName = c_setpointName[index];

if (m_com.GetFlagBool(COMPAT_FLAG_ENFORCE_MINSIZEPRECISION)) {
// Retain the size of the minimum temperature as the minimum field size for the temperature and the minimum precision as the base precision for future communication
node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint::SetPointMinSize, setpointName + "_setpointminsize", "B", false, false, size, 0);
node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint::SetPointPrecision, setpointName + "_setpointprecision", "D", false, false, min_precision, 0);
Log::Write(LogLevel_Info, GetNodeId(), "EnforceMinSizePrecision enabled, retained min size and min precision from capability report for setpoint command");
}
node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint::Unused_0_Minimum + index, setpointName + "_minimum", "C", false, false, minValue, 0);
node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint::Unused_0_Maximum + index, setpointName + "_maximum", "C", false, false, maxValue, 0);
Log::Write(LogLevel_Info, GetNodeId(), " Added setpoint: %s", setpointName.c_str());
Expand All @@ -270,15 +279,26 @@ namespace OpenZWave
{
Internal::VC::ValueDecimal const* value = static_cast<Internal::VC::ValueDecimal const*>(&_value);
uint8 scale = strcmp("C", value->GetUnits().c_str()) ? 1 : 0;
int8 setpointminsize = 0; // Minimum number of bytes to express the setpoint value, optionally cached from the capabilities report
int8 setpointprecision = 0; // Minimum precision express the setpoint value, optionally cached from the capabilities report

if (Internal::VC::ValueByte const *minsizeValue = static_cast<Internal::VC::ValueByte const*>(GetValue(_value.GetID().GetInstance(), ValueID_Index_ThermostatSetpoint::SetPointMinSize)))
{
setpointminsize = minsizeValue->GetValue();
}
if (Internal::VC::ValueByte const *precisionValue = static_cast<Internal::VC::ValueByte const*>(GetValue(_value.GetID().GetInstance(), ValueID_Index_ThermostatSetpoint::SetPointPrecision)))
{
setpointprecision = precisionValue->GetValue();
}

Msg* msg = new Msg("ThermostatSetpointCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true);
msg->SetInstance(this, _value.GetID().GetInstance());
msg->Append(GetNodeId());
msg->Append(4 + GetAppendValueSize(value->GetValue()));
msg->Append(4 + GetAppendValueSize(value->GetValue(), setpointminsize, setpointprecision));
msg->Append(GetCommandClassId());
msg->Append(ThermostatSetpointCmd_Set);
msg->Append((uint8_t) (value->GetID().GetIndex() & 0xFF));
AppendValue(msg, value->GetValue(), scale);
AppendValue(msg, value->GetValue(), scale, setpointminsize, setpointprecision);
msg->Append(GetDriver()->GetTransmitOptions());
GetDriver()->SendMsg(msg, Driver::MsgQueue_Send);
return true;
Expand Down