1 //----------------------------------------------------------------------------- 2 // 3 // SwitchBinary.cpp 4 // 5 // Implementation of the Z-Wave COMMAND_CLASS_SWITCH_BINARY 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 // spec: http://zwavepublic.com/sites/default/files/command_class_specs_2017A/SDS13781-3%20Z-Wave%20Application%20Command%20Class%20Specification.pdf 27 // pp. 78ff 28 //----------------------------------------------------------------------------- 29 30 #include "command_classes/CommandClasses.h" 31 #include "command_classes/SwitchBinary.h" 32 #include "command_classes/WakeUp.h" 33 #include "Defs.h" 34 #include "Msg.h" 35 #include "Driver.h" 36 #include "Node.h" 37 #include "platform/Log.h" 38 39 #include "value_classes/ValueBool.h" 40 #include "value_classes/ValueByte.h" 41 42 namespace OpenZWave 43 { 44 namespace Internal 45 { 46 namespace CC 47 { 48 49 enum SwitchBinaryCmd 50 { 51 SwitchBinaryCmd_Set = 0x01, 52 SwitchBinaryCmd_Get = 0x02, 53 SwitchBinaryCmd_Report = 0x03 54 }; 55 56 //----------------------------------------------------------------------------- 57 // <SwitchBinary::RequestState> 58 // Request current state from the device 59 //----------------------------------------------------------------------------- RequestState(uint32 const _requestFlags,uint8 const _instance,Driver::MsgQueue const _queue)60 bool SwitchBinary::RequestState(uint32 const _requestFlags, uint8 const _instance, Driver::MsgQueue const _queue) 61 { 62 if (_requestFlags & RequestFlag_Dynamic) 63 { 64 return RequestValue(_requestFlags, ValueID_Index_SwitchBinary::Level, _instance, _queue); 65 } 66 67 return false; 68 } 69 70 //----------------------------------------------------------------------------- 71 // <SwitchBinary::RequestValue> 72 // Request current value from the device 73 //----------------------------------------------------------------------------- RequestValue(uint32 const _requestFlags,uint16 const _dummy1,uint8 const _instance,Driver::MsgQueue const _queue)74 bool SwitchBinary::RequestValue(uint32 const _requestFlags, uint16 const _dummy1, // = 0 (not used) 75 uint8 const _instance, Driver::MsgQueue const _queue) 76 { 77 if (m_com.GetFlagBool(COMPAT_FLAG_GETSUPPORTED)) 78 { 79 Msg* msg = new Msg("SwitchBinaryCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId()); 80 msg->SetInstance(this, _instance); 81 msg->Append(GetNodeId()); 82 msg->Append(2); 83 msg->Append(GetCommandClassId()); 84 msg->Append(SwitchBinaryCmd_Get); 85 msg->Append(GetDriver()->GetTransmitOptions()); 86 GetDriver()->SendMsg(msg, _queue); 87 return true; 88 } 89 else 90 { 91 Log::Write(LogLevel_Info, GetNodeId(), "SwitchBinaryCmd_Get Not Supported on this node"); 92 } 93 return false; 94 } 95 96 //----------------------------------------------------------------------------- 97 // <SwitchBinary::HandleMsg> 98 // Handle a message from the Z-Wave network 99 //----------------------------------------------------------------------------- HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)100 bool SwitchBinary::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance // = 1 101 ) 102 { 103 if (SwitchBinaryCmd_Report == (SwitchBinaryCmd) _data[0]) 104 { 105 Log::Write(LogLevel_Info, GetNodeId(), "Received SwitchBinary report from node %d: level=%s", GetNodeId(), _data[1] ? "On" : "Off"); 106 107 // data[1] => Switch state 108 if (Internal::VC::ValueBool* value = static_cast<Internal::VC::ValueBool*>(GetValue(_instance, ValueID_Index_SwitchBinary::Level))) 109 { 110 value->OnValueRefreshed(_data[1] != 0); 111 value->Release(); 112 } 113 114 if (GetVersion() >= 2) 115 { 116 117 // data[2] => target state 118 if (Internal::VC::ValueBool* value = static_cast<Internal::VC::ValueBool*>(GetValue(_instance, ValueID_Index_SwitchBinary::TargetState))) 119 { 120 value->OnValueRefreshed(_data[2] != 0); 121 value->Release(); 122 } 123 124 // data[3] might be duration 125 if (_length > 3) 126 { 127 if (Internal::VC::ValueByte* value = static_cast<Internal::VC::ValueByte*>(GetValue(_instance, ValueID_Index_SwitchBinary::Duration))) 128 { 129 value->OnValueRefreshed(_data[3]); 130 value->Release(); 131 } 132 } 133 } 134 135 return true; 136 } 137 138 return false; 139 } 140 141 //----------------------------------------------------------------------------- 142 // <SwitchBinary::SetValue> 143 // Set the state of the switch 144 //----------------------------------------------------------------------------- SetValue(Internal::VC::Value const & _value)145 bool SwitchBinary::SetValue(Internal::VC::Value const& _value) 146 { 147 bool res = false; 148 uint8 instance = _value.GetID().GetInstance(); 149 150 switch (_value.GetID().GetIndex()) 151 { 152 case ValueID_Index_SwitchBinary::Level: 153 { 154 if (Internal::VC::ValueBool* value = static_cast<Internal::VC::ValueBool*>(GetValue(instance, ValueID_Index_SwitchBinary::Level))) 155 { 156 res = SetState(instance, (static_cast<Internal::VC::ValueBool const*>(&_value))->GetValue()); 157 value->Release(); 158 } 159 break; 160 } 161 case ValueID_Index_SwitchBinary::Duration: 162 { 163 if (Internal::VC::ValueByte* value = static_cast<Internal::VC::ValueByte*>(GetValue(instance, ValueID_Index_SwitchBinary::Duration))) 164 { 165 value->OnValueRefreshed((static_cast<Internal::VC::ValueByte const*>(&_value))->GetValue()); 166 value->Release(); 167 } 168 res = true; 169 break; 170 } 171 172 } 173 174 return res; 175 } 176 177 //----------------------------------------------------------------------------- 178 // <SwitchBinary::SetValueBasic> 179 // Update class values based in BASIC mapping 180 //----------------------------------------------------------------------------- SetValueBasic(uint8 const _instance,uint8 const _value)181 void SwitchBinary::SetValueBasic(uint8 const _instance, uint8 const _value) 182 { 183 // Send a request for new value to synchronize it with the BASIC set/report. 184 // In case the device is sleeping, we set the value anyway so the BASIC set/report 185 // stays in sync with it. We must be careful mapping the uint8 BASIC value 186 // into a class specific value. 187 // When the device wakes up, the real requested value will be retrieved. 188 RequestValue(0, 0, _instance, Driver::MsgQueue_Send); 189 if (Node* node = GetNodeUnsafe()) 190 { 191 if (Internal::CC::WakeUp* wakeUp = static_cast<Internal::CC::WakeUp*>(node->GetCommandClass(Internal::CC::WakeUp::StaticGetCommandClassId()))) 192 { 193 if (!wakeUp->IsAwake()) 194 { 195 if (Internal::VC::ValueBool* value = static_cast<Internal::VC::ValueBool*>(GetValue(_instance, 0))) 196 { 197 value->OnValueRefreshed(_value != 0); 198 value->Release(); 199 } 200 } 201 } 202 } 203 } 204 205 //----------------------------------------------------------------------------- 206 // <SwitchBinary::SetState> 207 // Set a new state for the switch 208 //----------------------------------------------------------------------------- SetState(uint8 const _instance,bool const _state)209 bool SwitchBinary::SetState(uint8 const _instance, bool const _state) 210 { 211 uint8 const nodeId = GetNodeId(); 212 uint8 const targetValue = _state ? 0xff : 0; 213 214 Log::Write(LogLevel_Info, nodeId, "SwitchBinary::Set - Setting to %s", _state ? "On" : "Off"); 215 Msg* msg = new Msg("SwitchBinaryCmd_Set", nodeId, REQUEST, FUNC_ID_ZW_SEND_DATA, true); 216 msg->SetInstance(this, _instance); 217 msg->Append(nodeId); 218 219 if (GetVersion() >= 2) 220 { 221 Internal::VC::ValueByte* durationValue = static_cast<Internal::VC::ValueByte*>(GetValue(_instance, ValueID_Index_SwitchBinary::Duration)); 222 uint8 duration = durationValue->GetValue(); 223 durationValue->Release(); 224 if (duration == 0xff) 225 { 226 Log::Write(LogLevel_Info, GetNodeId(), " Duration: Default"); 227 } 228 else if (duration >= 0x80) 229 { 230 Log::Write(LogLevel_Info, GetNodeId(), " Duration: %d minutes", duration - 0x7f); 231 } 232 else 233 { 234 Log::Write(LogLevel_Info, GetNodeId(), " Duration: %d seconds", duration); 235 } 236 237 msg->Append(4); 238 msg->Append(GetCommandClassId()); 239 msg->Append(SwitchBinaryCmd_Set); 240 msg->Append(targetValue); 241 msg->Append(duration); 242 } 243 else 244 { 245 msg->Append(3); 246 msg->Append(GetCommandClassId()); 247 msg->Append(SwitchBinaryCmd_Set); 248 msg->Append(targetValue); 249 } 250 251 msg->Append(GetDriver()->GetTransmitOptions()); 252 GetDriver()->SendMsg(msg, Driver::MsgQueue_Send); 253 return true; 254 } 255 256 //----------------------------------------------------------------------------- 257 // <SwitchBinary::CreateVars> 258 // Create the values managed by this command class 259 //----------------------------------------------------------------------------- CreateVars(uint8 const _instance)260 void SwitchBinary::CreateVars(uint8 const _instance) 261 { 262 if (Node* node = GetNodeUnsafe()) 263 { 264 if (GetVersion() >= 2) 265 { 266 node->CreateValueByte(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SwitchBinary::Duration, "Transition Duration", "", false, false, 0xff, 0); 267 node->CreateValueBool(ValueID::ValueGenre_System, GetCommandClassId(), _instance, ValueID_Index_SwitchBinary::TargetState, "Target State", "", true, false, true, 0); 268 } 269 node->CreateValueBool(ValueID::ValueGenre_User, GetCommandClassId(), _instance, ValueID_Index_SwitchBinary::Level, "Switch", "", false, false, false, 0); 270 } 271 } 272 } // namespace CC 273 } // namespace Internal 274 } // namespace OpenZWave 275