1 //----------------------------------------------------------------------------- 2 // 3 // TimeParameters.cpp 4 // 5 // Implementation of the Z-Wave COMMAND_CLASS_TIME_PARAMETERS 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 <time.h> 29 #include "command_classes/CommandClasses.h" 30 #include "command_classes/TimeParameters.h" 31 #include "Defs.h" 32 #include "Msg.h" 33 #include "Node.h" 34 #include "Driver.h" 35 #include "platform/Log.h" 36 #include "Utils.h" 37 38 #include "value_classes/ValueButton.h" 39 #include "value_classes/ValueString.h" 40 41 namespace OpenZWave 42 { 43 namespace Internal 44 { 45 namespace CC 46 { 47 48 enum TimeParametersCmd 49 { 50 TimeParametersCmd_Set = 0x01, 51 TimeParametersCmd_Get = 0x02, 52 TimeParametersCmd_Report = 0x03 53 }; 54 55 //----------------------------------------------------------------------------- 56 // <TimeParameters::TimeParameters> 57 // Constructor 58 //----------------------------------------------------------------------------- TimeParameters(uint32 const _homeId,uint8 const _nodeId)59 TimeParameters::TimeParameters(uint32 const _homeId, uint8 const _nodeId) : 60 CommandClass(_homeId, _nodeId) 61 { 62 SetStaticRequest(StaticRequest_Values); 63 } 64 65 //----------------------------------------------------------------------------- 66 // <TimeParameters::RequestState> 67 // Request current state from the device 68 //----------------------------------------------------------------------------- RequestState(uint32 const _requestFlags,uint8 const _instance,Driver::MsgQueue const _queue)69 bool TimeParameters::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) 70 { 71 if ((_requestFlags & RequestFlag_Static) && HasStaticRequest(StaticRequest_Values)) 72 { 73 return RequestValue(_requestFlags, 0, _instance, _queue); 74 } 75 76 return false; 77 } 78 79 //----------------------------------------------------------------------------- 80 // <TimeParameters::RequestValue> 81 // Request current value from the device 82 //----------------------------------------------------------------------------- RequestValue(uint32 const _requestFlags,uint16 const _dummy1,uint8 const _instance,Driver::MsgQueue const _queue)83 bool TimeParameters::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) 84 uint8 const _instance, Driver::MsgQueue const _queue) 85 { 86 if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) 87 { 88 Msg* msg = new Msg("TimeParametersCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); 89 msg->SetInstance(this, _instance); 90 msg->Append(GetNodeId()); 91 msg->Append(2); 92 msg->Append(GetCommandClassId()); 93 msg->Append(TimeParametersCmd_Get); 94 msg->Append(GetDriver()->GetTransmitOptions()); 95 GetDriver()->SendMsg(msg, _queue); 96 return true; 97 } 98 else 99 { 100 Log::Write(LogLevel_Info, GetNodeId(), "TimeParametersCmd_Get Not Supported on this node"); 101 } 102 return false; 103 } 104 105 //----------------------------------------------------------------------------- 106 // <TimeParameters::HandleMsg> 107 // Handle a message from the Z-Wave network 108 //----------------------------------------------------------------------------- HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)109 bool TimeParameters::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 110 ) 111 { 112 if (TimeParametersCmd_Report == (TimeParametersCmd) _data[0]) 113 { 114 uint16 year = (_data[1] << 8) + (_data[2] & 0xFF); 115 uint8 month = (_data[3] & 0x0F); 116 uint8 day = (_data[4] & 0x1F); 117 uint8 hour = (_data[5] & 0x1F); 118 uint8 minute = (_data[6] & 0x3F); 119 uint8 second = (_data[7] & 0x3F); 120 121 Log::Write(LogLevel_Info, GetNodeId(), "Received TimeParameters report: %02d/%02d/%04d %02d:%02d:%02d", (int) day, (int) month, (int) year, (int) hour, (int) minute, (int) second); 122 if (Internal::VC::ValueString* value = static_cast<Internal::VC::ValueString*>(GetValue(_instance, ValueID_Index_TimeParameters::Date))) 123 { 124 char msg[512]; 125 snprintf(msg, sizeof(msg), "%02d/%02d/%04d", (int) day, (int) month, (int) year); 126 value->OnValueRefreshed(msg); 127 value->Release(); 128 } 129 if (Internal::VC::ValueString* value = static_cast<Internal::VC::ValueString*>(GetValue(_instance, ValueID_Index_TimeParameters::Time))) 130 { 131 char msg[512]; 132 snprintf(msg, sizeof(msg), "%02d:%02d:%02d", (int) hour, (int) minute, (int) second); 133 value->OnValueRefreshed(msg); 134 value->Release(); 135 } 136 ClearStaticRequest(StaticRequest_Values); 137 return true; 138 } 139 140 return false; 141 } 142 143 //----------------------------------------------------------------------------- 144 // <TimeParameters::SetValue> 145 // Set a value in the Z-Wave device 146 //----------------------------------------------------------------------------- SetValue(Internal::VC::Value const & _value)147 bool TimeParameters::SetValue(Internal::VC::Value const& _value) 148 { 149 bool ret = false; 150 151 uint8 instance = _value.GetID().GetInstance(); 152 153 if ((ValueID::ValueType_Button == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_TimeParameters::Set)) 154 { 155 time_t rawtime; 156 struct tm *timeinfo; 157 time(&rawtime); 158 // use threadsafe verion of localtime. Reported by nihilus, 2019-04 159 // https://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html#Broken_002ddown-Time 160 struct tm xtm; 161 memset(&xtm, 0, sizeof(xtm)); 162 timeinfo = localtime_r(&rawtime, &xtm); 163 164 Msg* msg = new Msg("TimeParametersCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); 165 msg->SetInstance(this, instance); 166 msg->Append(GetNodeId()); 167 msg->Append(9); 168 msg->Append(GetCommandClassId()); 169 msg->Append(TimeParametersCmd_Set); 170 /* Year 1 */ 171 msg->Append(((timeinfo->tm_year + 1900) >> 8) & 0xFF); 172 /* Year 2 */ 173 msg->Append(((timeinfo->tm_year + 1900) & 0xFF)); 174 /* Month */ 175 msg->Append((timeinfo->tm_mon & 0x0F) + 1); 176 /* Day */ 177 msg->Append((timeinfo->tm_mday & 0x1F)); 178 /* Hour */ 179 msg->Append((timeinfo->tm_hour & 0x1F)); 180 /* Minute */ 181 msg->Append((timeinfo->tm_min & 0x3F)); 182 /* Second */ 183 msg->Append((timeinfo->tm_sec & 0x3F)); 184 msg->Append(GetDriver()->GetTransmitOptions()); 185 GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); 186 187 /* Refresh after we send updated date/time */ 188 SetStaticRequest(StaticRequest_Values); 189 ret = RequestValue(RequestFlag_Static, 0, instance, Driver::MsgQueue_Query); 190 } 191 if ((ValueID::ValueType_Button == _value.GetID().GetType()) && (_value.GetID().GetIndex() == ValueID_Index_TimeParameters::Refresh)) 192 { 193 SetStaticRequest(StaticRequest_Values); 194 ret = RequestValue(RequestFlag_Static, 0, instance, Driver::MsgQueue_Query); 195 } 196 197 return ret; 198 } 199 200 //----------------------------------------------------------------------------- 201 // <TimeParameters::CreateVars> 202 // Create the values managed by this command class 203 //----------------------------------------------------------------------------- CreateVars(uint8 const _instance)204 void TimeParameters::CreateVars(uint8 const _instance) 205 { 206 if (Node* node = GetNodeUnsafe()) 207 { 208 node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_TimeParameters::Date, "Date", "", true, false, "", 0); 209 node->CreateValueString(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_TimeParameters::Time, "Time", "", true, false, "", 0); 210 node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_TimeParameters::Set, "Set Date/Time", 0); 211 node->CreateValueButton(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_TimeParameters::Refresh, "Refresh Date/Time", 0); 212 213 } 214 } 215 } // namespace CC 216 } // namespace Internal 217 } // namespace OpenZWave 218