1 //-----------------------------------------------------------------------------
2 //
3 //	DoorLockLogging.cpp
4 //
5 //	Implementation of the Z-Wave COMMAND_CLASS_DOOR_LOCK_LOGGING
6 //
7 //	Copyright (c) 2014 Justin Hammond <justin@dynam.ac>
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/DoorLockLogging.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/ValueBool.h"
37 #include "value_classes/ValueByte.h"
38 #include "value_classes/ValueInt.h"
39 #include "value_classes/ValueString.h"
40 
41 #include "tinyxml.h"
42 
43 using namespace OpenZWave;
44 
45 enum DoorLockLoggingCmd
46 {
47 	DoorLockLoggingCmd_RecordSupported_Get		= 0x01,
48 	DoorLockLoggingCmd_RecordSupported_Report	= 0x02,
49 	DoorLockLoggingCmd_Record_Get				= 0x03,
50 	DoorLockLoggingCmd_Record_Report			= 0x04
51 };
52 
53 enum DoorLockEventType
54 {
55 	DoorLockEventType_LockCode						= 0x01,
56 	DoorLockEventType_UnLockCode					= 0x02,
57 	DoorLockEventType_LockButton					= 0x03,
58 	DoorLockEventType_UnLockButton  				= 0x04,
59 	DoorLockEventType_LockCodeOOSchedule			= 0x05,
60 	DoorLockEventType_UnLockCodeOOSchedule			= 0x06,
61 	DoorLockEventType_IllegalCode					= 0x07,
62 	DoorLockEventType_LockManual					= 0x08,
63 	DoorLockEventType_UnLockManual					= 0x09,
64 	DoorLockEventType_LockAuto						= 0x0A,
65 	DoorLockEventType_UnLockAuto					= 0x0B,
66 	DoorLockEventType_LockRemoteCode				= 0x0C,
67 	DoorLockEventType_UnLockRemoteCode				= 0x0D,
68 	DoorLockEventType_LockRemote					= 0x0E,
69 	DoorLockEventType_UnLockRemote					= 0x0F,
70 	DoorLockEventType_LockRemoteCodeOOSchedule		= 0x10,
71 	DoorLockEventType_UnLockRemoteCodeOOSchedule	= 0x11,
72 	DoorLockEventType_RemoteIllegalCode				= 0x12,
73 	DoorLockEventType_LockManual2					= 0x13,
74 	DoorLockEventType_UnlockManual2					= 0x14,
75 	DoorLockEventType_LockSecured					= 0x15,
76 	DoorLockEventType_LockUnsecured					= 0x16,
77 	DoorLockEventType_UserCodeAdded					= 0x17,
78 	DoorLockEventType_UserCodeDeleted				= 0x18,
79 	DoorLockEventType_AllUserCodesDeleted			= 0x19,
80 	DoorLockEventType_MasterCodeChanged				= 0x1A,
81 	DoorLockEventType_UserCodeChanged				= 0x1B,
82 	DoorLockEventType_LockReset						= 0x1C,
83 	DoorLockEventType_ConfigurationChanged			= 0x1D,
84 	DoorLockEventType_LowBattery					= 0x1E,
85 	DoorLockEventType_NewBattery					= 0x1F,
86 	DoorLockEventType_Max							= 0x20
87 };
88 
89 static char const* c_DoorLockEventType[] =
90 {
91 	"Locked via Access Code",
92 	"Unlocked via Access Code",
93 	"Locked via Lock Button",
94 	"Unlocked via UnLock Button",
95 	"Lock Attempt via Out of Schedule Access Code",
96 	"Unlock Attemp via Out of Schedule Access Code",
97 	"Illegal Access Code Entered",
98 	"Manually Locked",
99 	"Manually UnLocked",
100 	"Auto Locked",
101 	"Auto Unlocked",
102 	"Locked via Remote Out of Schedule Access Code",
103 	"Unlocked via Remote Out of Schedule Access Code",
104 	"Locked via Remote",
105 	"Unlocked via Remote",
106 	"Lock Attempt via Remote Out of Schedule Access Code",
107 	"Unlock Attempt via Remote Out of Schedule Access Code",
108 	"Illegal Remote Access Code",
109 	"Manually Locked (2)",
110 	"Manually Unlocked (2)",
111 	"Lock Secured",
112 	"Lock Unsecured",
113 	"User Code Added",
114 	"User Code Deleted",
115 	"All User Codes Deleted",
116 	"Master Code Changed",
117 	"User Code Changed",
118 	"Lock Reset",
119 	"Configuration Changed",
120 	"Low Battery",
121 	"New Battery Installed",
122 	"Unknown"
123 };
124 /* size = 31 entries */
125 
126 enum ValueIDSystemIndexes
127 {
128 	Value_System_Config_MaxRecords		= 0x00,		/* Max Number of Records the Device can Hold */
129 	Value_GetRecordNo					= 0x01,		/* Current Record Number after refresh */
130 	Value_LogRecord						= 0x02		/* Simple String Representation of the Log Record - Tab Delimited Fields */
131 };
132 
133 
134 
135 //-----------------------------------------------------------------------------
136 // <DoorLockLogging::DoorLockLogging>
137 // Constructor
138 //-----------------------------------------------------------------------------
DoorLockLogging(uint32 const _homeId,uint8 const _nodeId)139 DoorLockLogging::DoorLockLogging
140 (
141 	uint32 const _homeId,
142 	uint8 const _nodeId
143 ):
144 	CommandClass( _homeId, _nodeId ),
145 	m_MaxRecords(0),
146 	m_CurRecord(0)
147 {
148 	SetStaticRequest( StaticRequest_Values );
149 }
150 
151 //-----------------------------------------------------------------------------
152 // <UserCode::ReadXML>
153 // Class specific configuration
154 //-----------------------------------------------------------------------------
ReadXML(TiXmlElement const * _ccElement)155 void DoorLockLogging::ReadXML
156 (
157 	TiXmlElement const* _ccElement
158 )
159 {
160 	int32 intVal;
161 
162 	CommandClass::ReadXML( _ccElement );
163 	if( TIXML_SUCCESS == _ccElement->QueryIntAttribute( "m_MaxRecords", &intVal ) )
164 	{
165 		m_MaxRecords = intVal;
166 	}
167 }
168 
169 //-----------------------------------------------------------------------------
170 // <UserCode::WriteXML>
171 // Class specific configuration
172 //-----------------------------------------------------------------------------
WriteXML(TiXmlElement * _ccElement)173 void DoorLockLogging::WriteXML
174 (
175 	TiXmlElement* _ccElement
176 )
177 {
178 	char str[32];
179 
180 	CommandClass::WriteXML( _ccElement );
181 	snprintf( str, sizeof(str), "%d", m_MaxRecords );
182 	_ccElement->SetAttribute( "m_MaxRecords", str);
183 }
184 
185 
186 
187 //-----------------------------------------------------------------------------
188 // <DoorLockLogging::RequestState>
189 // Request current state from the device
190 //-----------------------------------------------------------------------------
RequestState(uint32 const _requestFlags,uint8 const _instance,Driver::MsgQueue const _queue)191 bool DoorLockLogging::RequestState
192 (
193 	uint32 const _requestFlags,
194 	uint8 const _instance,
195 	Driver::MsgQueue const _queue
196 )
197 {
198 	bool requests = false;
199 	if( ( _requestFlags & RequestFlag_Static ) && HasStaticRequest( StaticRequest_Values ) )
200 	{
201 		requests = RequestValue( _requestFlags, DoorLockLoggingCmd_RecordSupported_Get, _instance, _queue );
202 	}
203 
204 	if( _requestFlags & RequestFlag_Dynamic )
205 	{
206 		requests |= RequestValue( _requestFlags, DoorLockLoggingCmd_Record_Get, _instance, _queue );
207 	}
208 
209 	return requests;
210 }
211 
212 
213 
214 
215 //-----------------------------------------------------------------------------
216 // <DoorLockLogging::RequestValue>
217 // Request current value from the device
218 //-----------------------------------------------------------------------------
RequestValue(uint32 const _requestFlags,uint8 const _what,uint8 const _instance,Driver::MsgQueue const _queue)219 bool DoorLockLogging::RequestValue
220 (
221 	uint32 const _requestFlags,
222 	uint8 const _what,
223 	uint8 const _instance,
224 	Driver::MsgQueue const _queue
225 )
226 {
227 	if ( _what == DoorLockLoggingCmd_RecordSupported_Get) {
228 		Msg* msg = new Msg( "DoorLockLoggingCmd_RecordSupported_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
229 		msg->SetInstance( this, _instance );
230 		msg->Append( GetNodeId() );
231 		msg->Append( 2 );
232 		msg->Append( GetCommandClassId() );
233 		msg->Append( DoorLockLoggingCmd_RecordSupported_Get );
234 		msg->Append( GetDriver()->GetTransmitOptions() );
235 		GetDriver()->SendMsg( msg, _queue );
236 		return true;
237 
238 	} else if (_what == DoorLockLoggingCmd_Record_Get) {
239 		Msg* msg = new Msg( "DoorLockLoggingCmd_Record_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
240 		msg->SetInstance( this, _instance );
241 		msg->Append( GetNodeId() );
242 		msg->Append( 2 );
243 		msg->Append( GetCommandClassId() );
244 		msg->Append( DoorLockLoggingCmd_Record_Get );
245 		msg->Append( m_CurRecord );
246 		msg->Append( GetDriver()->GetTransmitOptions() );
247 		GetDriver()->SendMsg( msg, _queue );
248 		return true;
249 	}
250 	return false;
251 }
252 
253 
254 //-----------------------------------------------------------------------------
255 // <DoorLockLogging::HandleMsg>
256 // Handle a message from the Z-Wave network
257 //-----------------------------------------------------------------------------
HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)258 bool DoorLockLogging::HandleMsg
259 (
260 	uint8 const* _data,
261 	uint32 const _length,
262 	uint32 const _instance	// = 1
263 )
264 {
265 
266 	if( DoorLockLoggingCmd_RecordSupported_Report == (DoorLockLoggingCmd)_data[0] )
267 	{
268 		Log::Write( LogLevel_Info, GetNodeId(), "Received DoorLockLoggingCmd_RecordSupported_Report: Max Records is %d ", _data[1]);
269 		m_MaxRecords = _data[1];
270 		if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, Value_System_Config_MaxRecords ) ) )
271 		{
272 
273 			value->OnValueRefreshed( m_MaxRecords );
274 			value->Release();
275 		}
276 		ClearStaticRequest( StaticRequest_Values );
277 		return true;
278 	} else if (DoorLockLoggingCmd_Record_Report == (DoorLockLoggingCmd)_data[0] )
279 	{
280 		uint8 EventType = _data[9];
281 		if (EventType >= DoorLockEventType_Max)
282 			EventType = DoorLockEventType_Max;
283 
284 		Log::Write (LogLevel_Info, GetNodeId(), "Received a DoorLockLogging Record %d which is \"%s\"", _data[1], c_DoorLockEventType[EventType-1]);
285 
286 		if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, Value_GetRecordNo ) ) )
287 		{
288 			value->OnValueRefreshed( _data[1]);
289 			value->Release();
290 		}
291 		if( ValueString* value = static_cast<ValueString*>( GetValue( _instance, Value_LogRecord ) ) )
292 		{
293 			char msg[512];
294 			uint16 year = (_data[2] << 8) + (_data[3] & 0xFF);
295 			uint8 month = (_data[4] & 0x0F);
296 			uint8 day = (_data[5] & 0x1F);
297 			uint8 hour = (_data[6] & 0x1F);
298 			uint8 minute = (_data[7] & 0x3F);
299 			uint8 second = (_data[8] & 0x3F);
300 			bool valid = false;
301 			if (((_data[6] & 0xE0) >> 5) > 0)
302 			{
303 				valid = true;
304 			}
305 			uint8 userid = (_data[10]);
306 			uint8 usercodelength = (_data[11]);
307 			char usercode[254], tmpusercode[254];
308 			snprintf(usercode, sizeof(usercode), "UserCode:");
309 			if (usercodelength > 0)
310 				for (int i = 0; i < usercodelength; i++ )
311 				{
312 					strncpy(tmpusercode, usercode, sizeof(tmpusercode));
313                                         snprintf(usercode, sizeof(usercode), "%s %d", tmpusercode, (int)_data[12+i]);
314 				}
315 
316 			if (valid) {
317 				snprintf(msg, sizeof(msg), "%02d/%02d/%02d %02d:%02d:%02d \tMessage: %s \tUserID: %d \t%s", (int)day, (int)month, (int)year, (int)hour, (int)minute, (int)second, c_DoorLockEventType[EventType], (int)userid, usercode);
318 			} else
319 				snprintf(msg, sizeof(msg), "Invalid Record");
320 			value->OnValueRefreshed(msg);
321 			value->Release();
322 		}
323 		return true;
324 
325 	}
326 	return false;
327 }
328 
329 //-----------------------------------------------------------------------------
330 // <DoorLockLogging::SetValue>
331 // Set the lock's state
332 //-----------------------------------------------------------------------------
SetValue(Value const & _value)333 bool DoorLockLogging::SetValue
334 (
335 	Value const& _value
336 )
337 {
338 	if( (Value_GetRecordNo == _value.GetID().GetIndex()) && ValueID::ValueType_Byte == _value.GetID().GetType() )
339 	{
340 		ValueByte const* value = static_cast<ValueByte const*>(&_value);
341 
342 		Log::Write( LogLevel_Info, GetNodeId(), "DoorLockLoggingCmd_Record_Get - Requesting Log Record %d", value->GetValue() );
343 		Msg* msg = new Msg( "DoorLockLoggingCmd_Record_Get",  GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
344 		msg->SetInstance( this, _value.GetID().GetInstance() );
345 		msg->Append( GetNodeId() );
346 		msg->Append( 3 );
347 		msg->Append( GetCommandClassId() );
348 		msg->Append( DoorLockLoggingCmd_Record_Get );
349 		msg->Append( value->GetValue() );
350 		msg->Append( GetDriver()->GetTransmitOptions() );
351 		GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
352 		m_CurRecord = value->GetValue();
353 		return true;
354 	}
355 	return false;
356 }
357 
358 
359 
360 //-----------------------------------------------------------------------------
361 // <DoorLockLogging::CreateVars>
362 // Create the values managed by this command class
363 //-----------------------------------------------------------------------------
CreateVars(uint8 const _instance)364 void DoorLockLogging::CreateVars
365 (
366 	uint8 const _instance
367 )
368 {
369 	if( Node* node = GetNodeUnsafe() )
370 	{
371   		node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, Value_System_Config_MaxRecords, "Max Number of Records", "", true, false, 0x0, 0 );
372   		node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, Value_GetRecordNo, "Current Record Number", "", false, false, 0x0, 0 );
373   		node->CreateValueString( ValueID::ValueGenre_User, GetCommandClassId(), _instance, Value_LogRecord, "Log Record", "", true, false, "", 0 );
374 	}
375 }
376 
377 
378