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