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

Rough port of the fix for the Z-TERM3 thermostat from open-zwave 1.6 branch #220

Merged
merged 3 commits into from
Oct 4, 2023
Merged
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
6 changes: 6 additions & 0 deletions 00-JF-README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Patched version of the jeedom zwave plugin, working with the Heatit Z-TRM3

To install,
cd resources
sudo bash post_install.sh

3 changes: 3 additions & 0 deletions plugin_info/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"git" : {},
"python-pip" : {},
"python-dev" : {},
"python3-pyudev" : {},
"python3-requests" : {},
"python3-setuptools" : {},
"make" : {},
"build-essential" : {},
"libudev-dev" : {},
Expand Down
5 changes: 3 additions & 2 deletions resources/openzwaved/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 @@ -55,7 +56,7 @@ NB! Please use this procedure only when the primary controller/ gateway is missi

<CommandClass id="67">
<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"/>
<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" enforce_minsize_precision="true"/>
<Compatibility>
<Base>0</Base>
<CreateVars>true</CreateVars>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ m_afterMark( false ),
m_createVars( true ),
m_overridePrecision( -1 ),
m_getSupported( true ),
m_enforceMinSizePrecision( true ),
m_isSecured( false ),
m_SecureSupport( true ),
m_inNIF(false),
Expand Down Expand Up @@ -240,6 +241,12 @@ void CommandClass::ReadXML
m_afterMark = !strcmp( str, "true" );
}

str = _ccElement->Attribute( "enforce_minsize_precision" );
if( str )
{
m_enforceMinSizePrecision = !strcmp( str, "true" );
}

str = _ccElement->Attribute( "create_vars" );
if( str )
{
Expand Down Expand Up @@ -648,12 +655,14 @@ void CommandClass::AppendValue
(
Msg* _msg,
string const& _value,
uint8 const _scale
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 @@ -670,11 +679,13 @@ void CommandClass::AppendValue
//-----------------------------------------------------------------------------
uint8 const CommandClass::GetAppendValueSize
(
string const& _value
)const
string const& _value,
uint8 const _minsize,
uint8 const _minprecision
)const
{
uint8 size;
ValueToInteger( _value, NULL, &size );
ValueToInteger( _value, NULL, &size, _minsize, _minprecision);
return size;
}

Expand All @@ -687,7 +698,9 @@ int32 CommandClass::ValueToInteger
(
string const& _value,
uint8* o_precision,
uint8* o_size
uint8* o_size,
uint8 const _minsize,
uint8 const _minprecision
)const
{
int32 val;
Expand All @@ -714,8 +727,10 @@ int32 CommandClass::ValueToInteger
string str = _value.substr( 0, pos ) + _value.substr( pos+1 );
val = atol( str.c_str() );
}

if ( m_overridePrecision > 0 )
uint8 orp = m_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 < m_overridePrecision ) {
precision++;
Expand Down Expand Up @@ -751,6 +766,8 @@ int32 CommandClass::ValueToInteger
*o_size = 2;
}
}
if(*o_size < _minsize && (_minsize == 1 || _minsize == 2 || _minsize == 4))
*o_size = _minsize;
}

return val;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ namespace OpenZWave
* \param _scale A byte indicating the scale corresponding to this value (e.g., 1=F and 0=C for temperatures).
* \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 All @@ -144,6 +144,7 @@ namespace OpenZWave
protected:
virtual void CreateVars( uint8 const _instance ){}
void ReadValueRefreshXML ( TiXmlElement const* _ccElement );
bool m_enforceMinSizePrecision;

public:
virtual void CreateVars( uint8 const _instance, uint8 const _index ){}
Expand Down
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 All @@ -45,7 +46,9 @@ enum ThermostatSetpointCmd
ThermostatSetpointCmd_Get = 0x02,
ThermostatSetpointCmd_Report = 0x03,
ThermostatSetpointCmd_SupportedGet = 0x04,
ThermostatSetpointCmd_SupportedReport = 0x05
ThermostatSetpointCmd_SupportedReport = 0x05,
ThermostatSetpointCmd_CapabilitiesGet = 0x09,
ThermostatSetpointCmd_CapabilitiesReport = 0x0A
};

enum
Expand Down Expand Up @@ -257,6 +260,20 @@ bool ThermostatSetpoint::HandleMsg
{
if( ( _data[i] & (1<<bit) ) != 0 )
{
if (GetVersion() >= 3)
{
Msg* msg = new Msg("ThermostatSetpointCmd_CapabilitesGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId());
msg->SetInstance(this, _instance);
msg->Append(GetNodeId());
msg->Append(3);
msg->Append(GetCommandClassId());
msg->Append(ThermostatSetpointCmd_CapabilitiesGet);
uint8 type = ((i - 1) << 3) + bit;
msg->Append(type);
msg->Append(GetDriver()->GetTransmitOptions());
GetDriver()->SendMsg(msg, OpenZWave::Driver::MsgQueue_Query);
Log::Write(LogLevel_Info, GetNodeId(), " Requested Thermostat Setpoint Capabilities" );
}
// Add supported setpoint
int32 index = (int32)((i-1)<<3) + bit + m_setPointBase;
if( index < ThermostatSetpoint_Count )
Expand All @@ -273,6 +290,46 @@ bool ThermostatSetpoint::HandleMsg
return true;
}

if (ThermostatSetpointCmd_CapabilitiesReport == (ThermostatSetpointCmd) _data[0])
{
if (Node* node = GetNodeUnsafe())
{
// We have received the capabilities for supported setpoint Type
uint8 scale;
uint8 min_precision = 0;
uint8 max_precision = 0;
uint8 size = _data[2] & 0x07;
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 (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];

// JFD: Porting the Z-TRM3 minsize fix: branch 1.6 has a different way of managing ValueIDs and
// explicitely defines values for setpoint minsize and precision. The index part is 8 bits unsigned
// for both branches. We use an arbitrary unused index value for storing the minsize and precision.
// We don't store the minimum and maximum setpoint values as we have no use for them.
#define ValueID_Index_ThermostatSetpoint_SetPointMinSize 250
#define ValueID_Index_ThermostatSetpoint_SetPointPrecision 251

if (index < ThermostatSetpoint_Count)
{
string setpointName = c_setpointName[index];

if (m_enforceMinSizePrecision) {
// 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());
}

}
}
return false;
}

Expand All @@ -289,15 +346,26 @@ bool ThermostatSetpoint::SetValue
{
ValueDecimal const* value = static_cast<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 (auto const *minsizeValue = static_cast<ValueByte const*>(GetValue(_value.GetID().GetInstance(), ValueID_Index_ThermostatSetpoint_SetPointMinSize)))
{
setpointminsize = minsizeValue->GetValue();
}
if (auto const *precisionValue = static_cast<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( value->GetID().GetIndex() );
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
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ namespace OpenZWave
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
virtual bool SetValue( Value const& _value );
virtual uint8 GetMaxVersion(){ return 3; }

public:
virtual void CreateVars( uint8 const _instance, uint8 const _index );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ namespace OpenZWave
m_id = ((uint32)(id & 0xFFFFFFFF));
m_id1 = (uint32)(id >> 32);
}

// The default constructor has to be public for the class to be usable as an std::pair element.
ValueID():m_id(0),m_id1(0),m_homeId(0){}
private:
// Construct a value id for use in notifications
ValueID( uint32 const _homeId, uint8 const _nodeId ): m_id1( 0 ),m_homeId( _homeId ){ m_id = ((uint32)_nodeId)<<24; }
Expand All @@ -260,8 +263,6 @@ namespace OpenZWave
m_id1 = (((uint32)_instance)<<24);
}

// Default constructor
ValueID():m_id(0),m_id1(0),m_homeId(0){}

// Not all parts of the ValueID are necessary to uniquely identify the value. In the case of a
// Node's ValueStore, we can ignore the home ID, node ID, genre and type and still be left with
Expand Down