Skip to content

Commit

Permalink
Merge pull request #220 from medoc92/port-open-zwave-1.6-z-term3-fix
Browse files Browse the repository at this point in the history
Rough port of the fix for the Z-TERM3 thermostat from open-zwave 1.6 branch
  • Loading branch information
rocket13011 authored Oct 4, 2023
2 parents 14f148d + f303cdf commit a0d488a
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 18 deletions.
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

0 comments on commit a0d488a

Please sign in to comment.