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