Skip to content

Commit a0d488a

Browse files
authored
Merge pull request #220 from medoc92/port-open-zwave-1.6-z-term3-fix
Rough port of the fix for the Z-TERM3 thermostat from open-zwave 1.6 branch
2 parents 14f148d + f303cdf commit a0d488a

8 files changed

Lines changed: 116 additions & 18 deletions

File tree

00-JF-README.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Patched version of the jeedom zwave plugin, working with the Heatit Z-TRM3
2+
3+
To install,
4+
cd resources
5+
sudo bash post_install.sh
6+

plugin_info/packages.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"git" : {},
44
"python-pip" : {},
55
"python-dev" : {},
6+
"python3-pyudev" : {},
7+
"python3-requests" : {},
8+
"python3-setuptools" : {},
69
"make" : {},
710
"build-essential" : {},
811
"libudev-dev" : {},

resources/openzwaved/config/thermofloor/heatit058.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<Product Revision="1" xmlns="https://github.com/OpenZWave/open-zwave">
2+
<Product Revision="2" xmlns="https://github.com/OpenZWave/open-zwave">
33
<MetaData>
44
<MetaDataItem name="OzwInfoPage">http://www.openzwave.com/device-database/019B:0203:0003</MetaDataItem>
55
<MetaDataItem name="ProductPic">images/thermofloor/heatit058.png</MetaDataItem>
@@ -33,6 +33,7 @@ NB! Please use this procedure only when the primary controller/ gateway is missi
3333
<MetaDataItem name="Name">Heatit Z-TRM3</MetaDataItem>
3434
<ChangeLog>
3535
<Entry author="Sebastian Hatzl - sebihatzl@gmail.com" date="20 Aug 2020" revision="1">Initial Metadata Import from Z-Wave Alliance Database - https://products.z-wavealliance.org/products/3802/xml</Entry>
36+
<Entry author="Cyberwizzard - cyberwizzard+github@gmail.com" date="12 Nov 2020" revision="2">Enabled EnforceMinSizePrecision compatibility flag to fix the setpoint command</Entry>
3637
</ChangeLog>
3738
</MetaData>
3839
<CommandClass id="64">
@@ -55,7 +56,7 @@ NB! Please use this procedure only when the primary controller/ gateway is missi
5556

5657
<CommandClass id="67">
5758
<Instance index="1"/>
58-
<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"/>
59+
<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"/>
5960
<Compatibility>
6061
<Base>0</Base>
6162
<CreateVars>true</CreateVars>

resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ m_afterMark( false ),
6363
m_createVars( true ),
6464
m_overridePrecision( -1 ),
6565
m_getSupported( true ),
66+
m_enforceMinSizePrecision( true ),
6667
m_isSecured( false ),
6768
m_SecureSupport( true ),
6869
m_inNIF(false),
@@ -240,6 +241,12 @@ void CommandClass::ReadXML
240241
m_afterMark = !strcmp( str, "true" );
241242
}
242243

244+
str = _ccElement->Attribute( "enforce_minsize_precision" );
245+
if( str )
246+
{
247+
m_enforceMinSizePrecision = !strcmp( str, "true" );
248+
}
249+
243250
str = _ccElement->Attribute( "create_vars" );
244251
if( str )
245252
{
@@ -648,12 +655,14 @@ void CommandClass::AppendValue
648655
(
649656
Msg* _msg,
650657
string const& _value,
651-
uint8 const _scale
658+
uint8 const _scale,
659+
uint8 const _minsize,
660+
uint8 const _minprecision
652661
)const
653662
{
654663
uint8 precision;
655664
uint8 size;
656-
int32 val = ValueToInteger( _value, &precision, &size );
665+
int32 val = ValueToInteger( _value, &precision, &size, _minsize, _minprecision );
657666

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

@@ -670,11 +679,13 @@ void CommandClass::AppendValue
670679
//-----------------------------------------------------------------------------
671680
uint8 const CommandClass::GetAppendValueSize
672681
(
673-
string const& _value
674-
)const
682+
string const& _value,
683+
uint8 const _minsize,
684+
uint8 const _minprecision
685+
)const
675686
{
676687
uint8 size;
677-
ValueToInteger( _value, NULL, &size );
688+
ValueToInteger( _value, NULL, &size, _minsize, _minprecision);
678689
return size;
679690
}
680691

@@ -687,7 +698,9 @@ int32 CommandClass::ValueToInteger
687698
(
688699
string const& _value,
689700
uint8* o_precision,
690-
uint8* o_size
701+
uint8* o_size,
702+
uint8 const _minsize,
703+
uint8 const _minprecision
691704
)const
692705
{
693706
int32 val;
@@ -714,8 +727,10 @@ int32 CommandClass::ValueToInteger
714727
string str = _value.substr( 0, pos ) + _value.substr( pos+1 );
715728
val = atol( str.c_str() );
716729
}
717-
718-
if ( m_overridePrecision > 0 )
730+
uint8 orp = m_overridePrecision;
731+
if ( orp == 0 && _minprecision > 0 )
732+
orp = _minprecision; // Only if no override is given and a valid _minprecision is used, force the precision to _minprecision
733+
if ( orp > 0 )
719734
{
720735
while ( precision < m_overridePrecision ) {
721736
precision++;
@@ -751,6 +766,8 @@ int32 CommandClass::ValueToInteger
751766
*o_size = 2;
752767
}
753768
}
769+
if(*o_size < _minsize && (_minsize == 1 || _minsize == 2 || _minsize == 4))
770+
*o_size = _minsize;
754771
}
755772

756773
return val;

resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,9 @@ namespace OpenZWave
127127
* \param _scale A byte indicating the scale corresponding to this value (e.g., 1=F and 0=C for temperatures).
128128
* \see Msg
129129
*/
130-
void AppendValue( Msg* _msg, string const& _value, uint8 const _scale )const;
131-
uint8 const GetAppendValueSize( string const& _value )const;
132-
int32 ValueToInteger( string const& _value, uint8* o_precision, uint8* o_size )const;
130+
void AppendValue( Msg* _msg, string const& _value, uint8 const _scale, uint8 const _minsize = 0, uint8 const _minprecision = 0 )const;
131+
uint8 const GetAppendValueSize( string const& _value, uint8 const _minsize = 0, uint8 const _minprecision = 0 )const;
132+
int32 ValueToInteger( string const& _value, uint8* o_precision, uint8* o_size, uint8 const _minsize = 0, uint8 const _minprecision = 0 )const;
133133

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

@@ -144,6 +144,7 @@ namespace OpenZWave
144144
protected:
145145
virtual void CreateVars( uint8 const _instance ){}
146146
void ReadValueRefreshXML ( TiXmlElement const* _ccElement );
147+
bool m_enforceMinSizePrecision;
147148

148149
public:
149150
virtual void CreateVars( uint8 const _instance, uint8 const _index ){}

resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.cpp

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "platform/Log.h"
3535

3636
#include "value_classes/ValueDecimal.h"
37+
#include "value_classes/ValueByte.h"
3738

3839
#include "tinyxml.h"
3940

@@ -45,7 +46,9 @@ enum ThermostatSetpointCmd
4546
ThermostatSetpointCmd_Get = 0x02,
4647
ThermostatSetpointCmd_Report = 0x03,
4748
ThermostatSetpointCmd_SupportedGet = 0x04,
48-
ThermostatSetpointCmd_SupportedReport = 0x05
49+
ThermostatSetpointCmd_SupportedReport = 0x05,
50+
ThermostatSetpointCmd_CapabilitiesGet = 0x09,
51+
ThermostatSetpointCmd_CapabilitiesReport = 0x0A
4952
};
5053

5154
enum
@@ -257,6 +260,20 @@ bool ThermostatSetpoint::HandleMsg
257260
{
258261
if( ( _data[i] & (1<<bit) ) != 0 )
259262
{
263+
if (GetVersion() >= 3)
264+
{
265+
Msg* msg = new Msg("ThermostatSetpointCmd_CapabilitesGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId());
266+
msg->SetInstance(this, _instance);
267+
msg->Append(GetNodeId());
268+
msg->Append(3);
269+
msg->Append(GetCommandClassId());
270+
msg->Append(ThermostatSetpointCmd_CapabilitiesGet);
271+
uint8 type = ((i - 1) << 3) + bit;
272+
msg->Append(type);
273+
msg->Append(GetDriver()->GetTransmitOptions());
274+
GetDriver()->SendMsg(msg, OpenZWave::Driver::MsgQueue_Query);
275+
Log::Write(LogLevel_Info, GetNodeId(), " Requested Thermostat Setpoint Capabilities" );
276+
}
260277
// Add supported setpoint
261278
int32 index = (int32)((i-1)<<3) + bit + m_setPointBase;
262279
if( index < ThermostatSetpoint_Count )
@@ -273,6 +290,46 @@ bool ThermostatSetpoint::HandleMsg
273290
return true;
274291
}
275292

293+
if (ThermostatSetpointCmd_CapabilitiesReport == (ThermostatSetpointCmd) _data[0])
294+
{
295+
if (Node* node = GetNodeUnsafe())
296+
{
297+
// We have received the capabilities for supported setpoint Type
298+
uint8 scale;
299+
uint8 min_precision = 0;
300+
uint8 max_precision = 0;
301+
uint8 size = _data[2] & 0x07;
302+
string minValue = ExtractValue(&_data[2], &scale, &min_precision);
303+
string maxValue = ExtractValue(&_data[2 + size + 1], &scale, &max_precision);
304+
305+
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);
306+
307+
uint8 index = _data[1];
308+
309+
// JFD: Porting the Z-TRM3 minsize fix: branch 1.6 has a different way of managing ValueIDs and
310+
// explicitely defines values for setpoint minsize and precision. The index part is 8 bits unsigned
311+
// for both branches. We use an arbitrary unused index value for storing the minsize and precision.
312+
// We don't store the minimum and maximum setpoint values as we have no use for them.
313+
#define ValueID_Index_ThermostatSetpoint_SetPointMinSize 250
314+
#define ValueID_Index_ThermostatSetpoint_SetPointPrecision 251
315+
316+
if (index < ThermostatSetpoint_Count)
317+
{
318+
string setpointName = c_setpointName[index];
319+
320+
if (m_enforceMinSizePrecision) {
321+
// 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
322+
node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint_SetPointMinSize, setpointName + "_setpointminsize", "B", false, false, size, 0);
323+
node->CreateValueByte(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint_SetPointPrecision, setpointName + "_setpointprecision", "D", false, false, min_precision, 0);
324+
Log::Write(LogLevel_Info, GetNodeId(), "EnforceMinSizePrecision enabled, retained min size and min precision from capability report for setpoint command");
325+
}
326+
// node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint::Unused_0_Minimum + index, setpointName + "_minimum", "C", false, false, minValue, 0);
327+
// node->CreateValueDecimal(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_ThermostatSetpoint::Unused_0_Maximum + index, setpointName + "_maximum", "C", false, false, maxValue, 0);
328+
Log::Write(LogLevel_Info, GetNodeId(), " Added setpoint: %s", setpointName.c_str());
329+
}
330+
331+
}
332+
}
276333
return false;
277334
}
278335

@@ -289,15 +346,26 @@ bool ThermostatSetpoint::SetValue
289346
{
290347
ValueDecimal const* value = static_cast<ValueDecimal const*>(&_value);
291348
uint8 scale = strcmp( "C", value->GetUnits().c_str() ) ? 1 : 0;
349+
int8 setpointminsize = 0; // Minimum number of bytes to express the setpoint value, optionally cached from the capabilities report
350+
int8 setpointprecision = 0; // Minimum precision express the setpoint value, optionally cached from the capabilities report
351+
352+
if (auto const *minsizeValue = static_cast<ValueByte const*>(GetValue(_value.GetID().GetInstance(), ValueID_Index_ThermostatSetpoint_SetPointMinSize)))
353+
{
354+
setpointminsize = minsizeValue->GetValue();
355+
}
356+
if (auto const *precisionValue = static_cast<ValueByte const*>(GetValue(_value.GetID().GetInstance(), ValueID_Index_ThermostatSetpoint_SetPointPrecision)))
357+
{
358+
setpointprecision = precisionValue->GetValue();
359+
}
292360

293361
Msg* msg = new Msg( "ThermostatSetpointCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
294362
msg->SetInstance( this, _value.GetID().GetInstance() );
295363
msg->Append( GetNodeId() );
296-
msg->Append( 4 + GetAppendValueSize( value->GetValue() ) );
364+
msg->Append( 4 + GetAppendValueSize(value->GetValue(), setpointminsize, setpointprecision ) );
297365
msg->Append( GetCommandClassId() );
298366
msg->Append( ThermostatSetpointCmd_Set );
299367
msg->Append( value->GetID().GetIndex() );
300-
AppendValue( msg, value->GetValue(), scale );
368+
AppendValue( msg, value->GetValue(), scale, setpointminsize, setpointprecision );
301369
msg->Append( GetDriver()->GetTransmitOptions() );
302370
GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
303371
return true;

resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ namespace OpenZWave
5656
virtual string const GetCommandClassName()const{ return StaticGetCommandClassName(); }
5757
virtual bool HandleMsg( uint8 const* _data, uint32 const _length, uint32 const _instance = 1 );
5858
virtual bool SetValue( Value const& _value );
59+
virtual uint8 GetMaxVersion(){ return 3; }
5960

6061
public:
6162
virtual void CreateVars( uint8 const _instance, uint8 const _index );

resources/python-openzwave/openzwave/cpp/src/value_classes/ValueID.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ namespace OpenZWave
250250
m_id = ((uint32)(id & 0xFFFFFFFF));
251251
m_id1 = (uint32)(id >> 32);
252252
}
253+
254+
// The default constructor has to be public for the class to be usable as an std::pair element.
255+
ValueID():m_id(0),m_id1(0),m_homeId(0){}
253256
private:
254257
// Construct a value id for use in notifications
255258
ValueID( uint32 const _homeId, uint8 const _nodeId ): m_id1( 0 ),m_homeId( _homeId ){ m_id = ((uint32)_nodeId)<<24; }
@@ -260,8 +263,6 @@ namespace OpenZWave
260263
m_id1 = (((uint32)_instance)<<24);
261264
}
262265

263-
// Default constructor
264-
ValueID():m_id(0),m_id1(0),m_homeId(0){}
265266

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

0 commit comments

Comments
 (0)