diff --git a/00-JF-README.txt b/00-JF-README.txt new file mode 100644 index 000000000..8b65a8916 --- /dev/null +++ b/00-JF-README.txt @@ -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 + diff --git a/plugin_info/packages.json b/plugin_info/packages.json index 39b971b1e..c865236ce 100644 --- a/plugin_info/packages.json +++ b/plugin_info/packages.json @@ -3,6 +3,9 @@ "git" : {}, "python-pip" : {}, "python-dev" : {}, + "python3-pyudev" : {}, + "python3-requests" : {}, + "python3-setuptools" : {}, "make" : {}, "build-essential" : {}, "libudev-dev" : {}, diff --git a/resources/openzwaved/config/thermofloor/heatit058.xml b/resources/openzwaved/config/thermofloor/heatit058.xml index a97cc9abe..4d31a1de1 100644 --- a/resources/openzwaved/config/thermofloor/heatit058.xml +++ b/resources/openzwaved/config/thermofloor/heatit058.xml @@ -1,5 +1,5 @@ - + http://www.openzwave.com/device-database/019B:0203:0003 images/thermofloor/heatit058.png @@ -33,6 +33,7 @@ NB! Please use this procedure only when the primary controller/ gateway is missi Heatit Z-TRM3 Initial Metadata Import from Z-Wave Alliance Database - https://products.z-wavealliance.org/products/3802/xml + Enabled EnforceMinSizePrecision compatibility flag to fix the setpoint command @@ -55,7 +56,7 @@ NB! Please use this procedure only when the primary controller/ gateway is missi - + 0 true diff --git a/resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.cpp b/resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.cpp index 4b3961b3f..fb76f9d3c 100644 --- a/resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.cpp +++ b/resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.cpp @@ -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), @@ -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 ) { @@ -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< 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++; @@ -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; diff --git a/resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.h b/resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.h index 2fdede822..957d1437a 100644 --- a/resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.h +++ b/resources/python-openzwave/openzwave/cpp/src/command_classes/CommandClass.h @@ -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 @@ -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 ){} diff --git a/resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.cpp b/resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.cpp index 73d6772c7..121b95335 100644 --- a/resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.cpp +++ b/resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.cpp @@ -34,6 +34,7 @@ #include "platform/Log.h" #include "value_classes/ValueDecimal.h" +#include "value_classes/ValueByte.h" #include "tinyxml.h" @@ -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 @@ -257,6 +260,20 @@ bool ThermostatSetpoint::HandleMsg { if( ( _data[i] & (1<= 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 ) @@ -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; } @@ -289,15 +346,26 @@ bool ThermostatSetpoint::SetValue { ValueDecimal const* value = static_cast(&_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(GetValue(_value.GetID().GetInstance(), ValueID_Index_ThermostatSetpoint_SetPointMinSize))) + { + setpointminsize = minsizeValue->GetValue(); + } + if (auto const *precisionValue = static_cast(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; diff --git a/resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.h b/resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.h index 595e0d30d..bb85fe126 100644 --- a/resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.h +++ b/resources/python-openzwave/openzwave/cpp/src/command_classes/ThermostatSetpoint.h @@ -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 ); diff --git a/resources/python-openzwave/openzwave/cpp/src/value_classes/ValueID.h b/resources/python-openzwave/openzwave/cpp/src/value_classes/ValueID.h index ea183bf0d..be368829d 100644 --- a/resources/python-openzwave/openzwave/cpp/src/value_classes/ValueID.h +++ b/resources/python-openzwave/openzwave/cpp/src/value_classes/ValueID.h @@ -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; } @@ -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