1 //-----------------------------------------------------------------------------
2 //
3 // Alarm.cpp
4 //
5 // Implementation of the Z-Wave COMMAND_CLASS_ALARM
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/Alarm.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/ValueByte.h"
37
38 using namespace OpenZWave;
39
40 enum AlarmCmd
41 {
42 AlarmCmd_Get = 0x04,
43 AlarmCmd_Report = 0x05,
44 // Version 2
45 AlarmCmd_SupportedGet = 0x07,
46 AlarmCmd_SupportedReport = 0x08
47 };
48
49 enum
50 {
51 AlarmIndex_Type = 0,
52 AlarmIndex_Level,
53 AlarmIndex_SourceNodeId
54 };
55
56 enum
57 {
58 Alarm_General = 0,
59 Alarm_Smoke,
60 Alarm_CarbonMonoxide,
61 Alarm_CarbonDioxide,
62 Alarm_Heat,
63 Alarm_Flood,
64 Alarm_Access_Control,
65 Alarm_Burglar,
66 Alarm_Power_Management,
67 Alarm_System,
68 Alarm_Emergency,
69 Alarm_Clock,
70 Alarm_Appliance,
71 Alarm_HomeHealth,
72 Alarm_Count
73 };
74
75 static char const* c_alarmTypeName[] =
76 {
77 "General",
78 "Smoke",
79 "Carbon Monoxide",
80 "Carbon Dioxide",
81 "Heat",
82 "Flood",
83 "Access Control",
84 "Burglar",
85 "Power Management",
86 "System",
87 "Emergency",
88 "Clock",
89 "Appliance",
90 "HomeHealth"
91 };
92
93 //-----------------------------------------------------------------------------
94 // <WakeUp::WakeUp>
95 // Constructor
96 //-----------------------------------------------------------------------------
Alarm(uint32 const _homeId,uint8 const _nodeId)97 Alarm::Alarm
98 (
99 uint32 const _homeId,
100 uint8 const _nodeId
101 ):
102 CommandClass( _homeId, _nodeId )
103 {
104 SetStaticRequest( StaticRequest_Values );
105 }
106
107
108 //-----------------------------------------------------------------------------
109 // <Alarm::RequestState>
110 // Request current state from the device
111 //-----------------------------------------------------------------------------
RequestState(uint32 const _requestFlags,uint8 const _instance,Driver::MsgQueue const _queue)112 bool Alarm::RequestState
113 (
114 uint32 const _requestFlags,
115 uint8 const _instance,
116 Driver::MsgQueue const _queue
117 )
118 {
119 if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
120 {
121 if( GetVersion() > 1 )
122 {
123 // Request the supported alarm types
124 Msg* msg = new Msg( "AlarmCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
125 msg->SetInstance( this, _instance );
126 msg->Append( GetNodeId() );
127 msg->Append( 2 );
128 msg->Append( GetCommandClassId() );
129 msg->Append( AlarmCmd_SupportedGet );
130 msg->Append( GetDriver()->GetTransmitOptions() );
131 GetDriver()->SendMsg( msg, _queue );
132 return true;
133 }
134 }
135
136 if( _requestFlags & RequestFlag_Dynamic )
137 {
138 return RequestValue( _requestFlags, 0, _instance, _queue );
139 }
140
141 return false;
142 }
143
144 //-----------------------------------------------------------------------------
145 // <Alarm::RequestValue>
146 // Request current value from the device
147 //-----------------------------------------------------------------------------
RequestValue(uint32 const _requestFlags,uint8 const _dummy1,uint8 const _instance,Driver::MsgQueue const _queue)148 bool Alarm::RequestValue
149 (
150 uint32 const _requestFlags,
151 uint8 const _dummy1, // = 0 (not used)
152 uint8 const _instance,
153 Driver::MsgQueue const _queue
154 )
155 {
156 if( IsGetSupported() )
157 {
158 if( GetVersion() == 1 )
159 {
160 Msg* msg = new Msg( "AlarmCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
161 msg->SetInstance( this, _instance );
162 msg->Append( GetNodeId() );
163 msg->Append( 2 );
164 msg->Append( GetCommandClassId() );
165 msg->Append( AlarmCmd_Get );
166 msg->Append( GetDriver()->GetTransmitOptions() );
167 GetDriver()->SendMsg( msg, _queue );
168 return true;
169 }
170 else
171 {
172 bool res = false;
173 for( uint8 i = 0; i < Alarm_Count; i++ )
174 {
175 if( Value* value = GetValue( _instance, i + 3 ) ) {
176 value->Release();
177 Msg* msg = new Msg( "AlarmCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
178 msg->SetInstance( this, _instance );
179 msg->Append( GetNodeId() );
180 msg->Append( GetVersion() == 2 ? 4 : 5);
181 msg->Append( GetCommandClassId() );
182 msg->Append( AlarmCmd_Get );
183 msg->Append( 0x00); // ? proprietary alarm ?
184 msg->Append( i );
185 if( GetVersion() > 2 )
186 msg->Append(0x01); //get first event of type.
187 msg->Append( GetDriver()->GetTransmitOptions() );
188 GetDriver()->SendMsg( msg, _queue );
189 res = true;
190 }
191 }
192 return res;
193 }
194 } else {
195 Log::Write( LogLevel_Info, GetNodeId(), "AlarmCmd_Get Not Supported on this node");
196 }
197 return false;
198 }
199
200 //-----------------------------------------------------------------------------
201 // <Alarm::HandleMsg>
202 // Handle a message from the Z-Wave network
203 //-----------------------------------------------------------------------------
HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)204 bool Alarm::HandleMsg
205 (
206 uint8 const* _data,
207 uint32 const _length,
208 uint32 const _instance // = 1
209 )
210 {
211 if (AlarmCmd_Report == (AlarmCmd)_data[0])
212 {
213 // We have received a report from the Z-Wave device
214 if( GetVersion() == 1 )
215 {
216 Log::Write( LogLevel_Info, GetNodeId(), "Received Alarm report: type=%d, level=%d", _data[1], _data[2] );
217 }
218 else
219 {
220 string alarm_type = ( _data[5] < Alarm_Count ) ? c_alarmTypeName[_data[5]] : "Unknown type";
221
222 Log::Write( LogLevel_Info, GetNodeId(), "Received Alarm report: type=%d, level=%d, sensorSrcID=%d, type:%s event:%d, status=%d",
223 _data[1], _data[2], _data[3], alarm_type.c_str(), _data[6], _data[4] );
224 }
225
226 ValueByte* value;
227 if( (value = static_cast<ValueByte*>( GetValue( _instance, AlarmIndex_Type ) )) )
228 {
229 value->OnValueRefreshed( _data[1] );
230 value->Release();
231 }
232 if( (value = static_cast<ValueByte*>( GetValue( _instance, AlarmIndex_Level ) )) )
233 {
234 value->OnValueRefreshed( _data[2] );
235 value->Release();
236 }
237
238 // With Version=2, the data has more detailed information about the alarm
239 if(( GetVersion() > 1 ) && ( _length >= 7 ))
240 {
241 if( (value = static_cast<ValueByte*>( GetValue( _instance, AlarmIndex_SourceNodeId ) )) )
242 {
243 value->OnValueRefreshed( _data[3] );
244 value->Release();
245 }
246
247 if( (value = static_cast<ValueByte*>( GetValue( _instance, _data[5]+3 ) )) )
248 {
249 value->OnValueRefreshed( _data[6] );
250 value->Release();
251 }
252 }
253
254 return true;
255 }
256
257 if( AlarmCmd_SupportedReport == (AlarmCmd)_data[0] )
258 {
259 if( Node* node = GetNodeUnsafe() )
260 {
261 // We have received the supported alarm types from the Z-Wave device
262 Log::Write( LogLevel_Info, GetNodeId(), "Received supported alarm types" );
263
264 node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, AlarmIndex_SourceNodeId, "SourceNodeId", "", true, false, 0, 0 );
265 Log::Write( LogLevel_Info, GetNodeId(), " Added alarm SourceNodeId" );
266
267 // Parse the data for the supported alarm types
268 uint8 numBytes = _data[1];
269 for( uint32 i=0; i<numBytes; ++i )
270 {
271 for( int32 bit=0; bit<8; ++bit )
272 {
273 if( ( _data[i+2] & (1<<bit) ) != 0 )
274 {
275 int32 index = (int32)(i<<3) + bit;
276 if( index < Alarm_Count )
277 {
278 node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, index+3, c_alarmTypeName[index], "", true, false, 0, 0 );
279 Log::Write( LogLevel_Info, GetNodeId(), " Added alarm type: %s", c_alarmTypeName[index] );
280 } else {
281 Log::Write( LogLevel_Info, GetNodeId(), " Unknown alarm type: %d", index );
282 }
283 }
284 }
285 }
286 }
287
288 ClearStaticRequest( StaticRequest_Values );
289 return true;
290 }
291
292 return false;
293 }
294
295 //-----------------------------------------------------------------------------
296 // <Alarm::CreateVars>
297 // Create the values managed by this command class
298 //-----------------------------------------------------------------------------
CreateVars(uint8 const _instance)299 void Alarm::CreateVars
300 (
301 uint8 const _instance
302 )
303 {
304 if( Node* node = GetNodeUnsafe() )
305 {
306 node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, AlarmIndex_Type, "Alarm Type", "", true, false, 0, 0 );
307 node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, AlarmIndex_Level, "Alarm Level", "", true, false, 0, 0 );
308 }
309 }
310
311