1 //-----------------------------------------------------------------------------
2 //
3 // ThermostatSetpoint.cpp
4 //
5 // Implementation of the Z-Wave COMMAND_CLASS_THERMOSTAT_SETPOINT
6 //
7 // Copyright (c) 2010 Mal Lansell <openzwave@lansell.org>
8 //
9 // SOFTWARE NOTICE AND LICENSE
10 //
11 // This file is part of OpenZWave.
12 //
13 // OpenZWave is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU Lesser General Public License as published
15 // by the Free Software Foundation, either version 3 of the License,
16 // or (at your option) any later version.
17 //
18 // OpenZWave is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU Lesser General Public License for more details.
22 //
23 // You should have received a copy of the GNU Lesser General Public License
24 // along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
25 //
26 //-----------------------------------------------------------------------------
27
28 #include "command_classes/CommandClasses.h"
29 #include "command_classes/ThermostatSetpoint.h"
30 #include "Defs.h"
31 #include "Msg.h"
32 #include "Node.h"
33 #include "Driver.h"
34 #include "platform/Log.h"
35
36 #include "value_classes/ValueDecimal.h"
37
38 #include "tinyxml.h"
39
40 using namespace OpenZWave;
41
42 enum ThermostatSetpointCmd
43 {
44 ThermostatSetpointCmd_Set = 0x01,
45 ThermostatSetpointCmd_Get = 0x02,
46 ThermostatSetpointCmd_Report = 0x03,
47 ThermostatSetpointCmd_SupportedGet = 0x04,
48 ThermostatSetpointCmd_SupportedReport = 0x05
49 };
50
51 enum
52 {
53 ThermostatSetpoint_Unused0 = 0,
54 ThermostatSetpoint_Heating1,
55 ThermostatSetpoint_Cooling1,
56 ThermostatSetpoint_Unused3,
57 ThermostatSetpoint_Unused4,
58 ThermostatSetpoint_Unused5,
59 ThermostatSetpoint_Unused6,
60 ThermostatSetpoint_Furnace,
61 ThermostatSetpoint_DryAir,
62 ThermostatSetpoint_MoistAir,
63 ThermostatSetpoint_AutoChangeover,
64 ThermostatSetpoint_HeatingEcon,
65 ThermostatSetpoint_CoolingEcon,
66 ThermostatSetpoint_AwayHeating,
67 ThermostatSetpoint_Count
68 };
69
70 static char const* c_setpointName[] =
71 {
72 "Unused 0",
73 "Heating 1",
74 "Cooling 1",
75 "Unused 3",
76 "Unused 4",
77 "Unused 5",
78 "Unused 6",
79 "Furnace",
80 "Dry Air",
81 "Moist Air",
82 "Auto Changeover",
83 "Heating Econ",
84 "Cooling Econ",
85 "Away Heating"
86 };
87
88 //-----------------------------------------------------------------------------
89 // <ThermostatSetpoint::ThermostatSetpoint>
90 // Constructor
91 //-----------------------------------------------------------------------------
ThermostatSetpoint(uint32 const _homeId,uint8 const _nodeId)92 ThermostatSetpoint::ThermostatSetpoint
93 (
94 uint32 const _homeId,
95 uint8 const _nodeId
96 ):
97 CommandClass( _homeId, _nodeId ), m_setPointBase( 1 )
98 {
99 SetStaticRequest( StaticRequest_Values );
100 }
101
102 //-----------------------------------------------------------------------------
103 // <ThermostatSetpoint::ReadXML>
104 // Read the saved change-counter value
105 //-----------------------------------------------------------------------------
ReadXML(TiXmlElement const * _ccElement)106 void ThermostatSetpoint::ReadXML
107 (
108 TiXmlElement const* _ccElement
109 )
110 {
111 CommandClass::ReadXML( _ccElement );
112
113 int intVal;
114 if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "base", &intVal ) )
115 {
116 m_setPointBase = (uint8)intVal;
117 }
118 }
119
120 //-----------------------------------------------------------------------------
121 // <ThermostatSetpoint::WriteXML>
122 // Write the change-counter value
123 //-----------------------------------------------------------------------------
WriteXML(TiXmlElement * _ccElement)124 void ThermostatSetpoint::WriteXML
125 (
126 TiXmlElement* _ccElement
127 )
128 {
129 CommandClass::WriteXML( _ccElement );
130
131 char str[8];
132 snprintf( str, 8, "%d", m_setPointBase );
133 _ccElement->SetAttribute( "base", str );
134 }
135
136 //-----------------------------------------------------------------------------
137 // <ThermostatSetpoint::RequestState>
138 // Get the static thermostat setpoint details from the device
139 //-----------------------------------------------------------------------------
RequestState(uint32 const _requestFlags,uint8 const _instance,Driver::MsgQueue const _queue)140 bool ThermostatSetpoint::RequestState
141 (
142 uint32 const _requestFlags,
143 uint8 const _instance,
144 Driver::MsgQueue const _queue
145 )
146 {
147 bool requests = false;
148 if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
149 {
150 requests |= RequestValue( _requestFlags, 0xff, _instance, _queue );
151 }
152
153 if( _requestFlags & RequestFlag_Session )
154 {
155 for( uint8 i=0; i<ThermostatSetpoint_Count; ++i )
156 {
157 requests |= RequestValue( _requestFlags, i, _instance, _queue );
158 }
159 }
160
161 return requests;
162 }
163
164 //-----------------------------------------------------------------------------
165 // <ThermostatSetpoint::RequestValue>
166 // Request current state from the device
167 //-----------------------------------------------------------------------------
RequestValue(uint32 const _requestFlags,uint8 const _setPointIndex,uint8 const _instance,Driver::MsgQueue const _queue)168 bool ThermostatSetpoint::RequestValue
169 (
170 uint32 const _requestFlags,
171 uint8 const _setPointIndex,
172 uint8 const _instance,
173 Driver::MsgQueue const _queue
174 )
175 {
176 if( _setPointIndex == 0xff ) // check for supportedget
177 {
178 // Request the supported setpoints
179 Msg* msg = new Msg( "ThermostatSetpointCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
180 msg->SetInstance( this, _instance );
181 msg->Append( GetNodeId() );
182 msg->Append( 2 );
183 msg->Append( GetCommandClassId() );
184 msg->Append( ThermostatSetpointCmd_SupportedGet );
185 msg->Append( GetDriver()->GetTransmitOptions() );
186 GetDriver()->SendMsg( msg, _queue );
187 return true;
188 }
189 if ( !IsGetSupported() )
190 {
191 Log::Write( LogLevel_Info, GetNodeId(), "ThermostatSetpointCmd_Get Not Supported on this node");
192 return false;
193 }
194 Value* value = GetValue( 1, _setPointIndex );
195 if( value != NULL )
196 {
197 value->Release();
198 // Request the setpoint value
199 Msg* msg = new Msg( "ThermostatSetpointCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
200 msg->SetInstance( this, _instance );
201 msg->Append( GetNodeId() );
202 msg->Append( 3 );
203 msg->Append( GetCommandClassId() );
204 msg->Append( ThermostatSetpointCmd_Get );
205 msg->Append( _setPointIndex );
206 msg->Append( GetDriver()->GetTransmitOptions() );
207 GetDriver()->SendMsg( msg, _queue );
208 return true;
209 }
210 return false;
211 }
212
213 //-----------------------------------------------------------------------------
214 // <ThermostatSetpoint::HandleMsg>
215 // Handle a message from the Z-Wave network
216 //-----------------------------------------------------------------------------
HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)217 bool ThermostatSetpoint::HandleMsg
218 (
219 uint8 const* _data,
220 uint32 const _length,
221 uint32 const _instance // = 1
222 )
223 {
224 if( ThermostatSetpointCmd_Report == (ThermostatSetpointCmd)_data[0] )
225 {
226 // We have received a thermostat setpoint value from the Z-Wave device
227 if( ValueDecimal* value = static_cast<ValueDecimal*>( GetValue( _instance, _data[1] ) ) )
228 {
229 uint8 scale;
230 uint8 precision = 0;
231 string temperature = ExtractValue( &_data[2], &scale, &precision );
232
233 value->SetUnits( scale ? "F" : "C" );
234 value->OnValueRefreshed( temperature );
235 if( value->GetPrecision() != precision )
236 {
237 value->SetPrecision( precision );
238 }
239 value->Release();
240
241 Log::Write( LogLevel_Info, GetNodeId(), "Received thermostat setpoint report: Setpoint %s = %s%s", value->GetLabel().c_str(), value->GetValue().c_str(), value->GetUnits().c_str() );
242 }
243 return true;
244 }
245
246 if( ThermostatSetpointCmd_SupportedReport == (ThermostatSetpointCmd)_data[0] )
247 {
248 if( Node* node = GetNodeUnsafe() )
249 {
250 // We have received the supported thermostat setpoints from the Z-Wave device
251 Log::Write( LogLevel_Info, GetNodeId(), "Received supported thermostat setpoints" );
252
253 // Parse the data for the supported setpoints
254 for( uint32 i=1; i<_length-1; ++i )
255 {
256 for( int32 bit=0; bit<8; ++bit )
257 {
258 if( ( _data[i] & (1<<bit) ) != 0 )
259 {
260 // Add supported setpoint
261 int32 index = (int32)((i-1)<<3) + bit + m_setPointBase;
262 if( index < ThermostatSetpoint_Count )
263 {
264 node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, index, c_setpointName[index], "C", false, false, "0.0", 0 );
265 Log::Write( LogLevel_Info, GetNodeId(), " Added setpoint: %s", c_setpointName[index] );
266 }
267 }
268 }
269 }
270 }
271
272 ClearStaticRequest( StaticRequest_Values );
273 return true;
274 }
275
276 return false;
277 }
278
279 //-----------------------------------------------------------------------------
280 // <ThermostatSetpoint::SetValue>
281 // Set a thermostat setpoint temperature
282 //-----------------------------------------------------------------------------
SetValue(Value const & _value)283 bool ThermostatSetpoint::SetValue
284 (
285 Value const& _value
286 )
287 {
288 if( ValueID::ValueType_Decimal == _value.GetID().GetType() )
289 {
290 ValueDecimal const* value = static_cast<ValueDecimal const*>(&_value);
291 uint8 scale = strcmp( "C", value->GetUnits().c_str() ) ? 1 : 0;
292
293 Msg* msg = new Msg( "ThermostatSetpointCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
294 msg->SetInstance( this, _value.GetID().GetInstance() );
295 msg->Append( GetNodeId() );
296 msg->Append( 4 + GetAppendValueSize( value->GetValue() ) );
297 msg->Append( GetCommandClassId() );
298 msg->Append( ThermostatSetpointCmd_Set );
299 msg->Append( value->GetID().GetIndex() );
300 AppendValue( msg, value->GetValue(), scale );
301 msg->Append( GetDriver()->GetTransmitOptions() );
302 GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
303 return true;
304 }
305
306 return false;
307 }
308
309 //-----------------------------------------------------------------------------
310 // <ThermostatSetpoint::CreateVars>
311 // Create the values managed by this command class
312 //-----------------------------------------------------------------------------
CreateVars(uint8 const _instance,uint8 const _index)313 void ThermostatSetpoint::CreateVars
314 (
315 uint8 const _instance,
316 uint8 const _index
317 )
318 {
319 if( Node* node = GetNodeUnsafe() )
320 {
321 node->CreateValueDecimal( ValueID::ValueGenre_User, GetCommandClassId(), _instance, _index, "Setpoint", "C", false, false, "0.0", 0 );
322 }
323 }
324