Skip to content

Commit 221cbaf

Browse files
authored
Merge pull request #2584 from markruys/feature/Supervision_Thermostat
Use supervision to set thermostat setpoint
2 parents a8aa634 + 8113401 commit 221cbaf

13 files changed

Lines changed: 481 additions & 32 deletions

File tree

cpp/src/Msg.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "ZWSecurity.h"
3434
#include "platform/Log.h"
3535
#include "command_classes/MultiInstance.h"
36+
#include "command_classes/Supervision.h"
3637
#include "command_classes/Security.h"
3738
#include "aes/aescpp.h"
3839

@@ -50,7 +51,7 @@ namespace OpenZWave
5051
//-----------------------------------------------------------------------------
5152
Msg::Msg(string const& _logText, uint8 _targetNodeId, uint8 const _msgType, uint8 const _function, bool const _bCallbackRequired, bool const _bReplyRequired, // = true
5253
uint8 const _expectedReply, // = 0
53-
uint8 const _expectedCommandClassId // = 0
54+
uint8 const _expectedCommandClassId // = 0
5455
) :
5556
m_logText(_logText), m_bFinal(false), m_bCallbackRequired(_bCallbackRequired), m_callbackId(0), m_expectedReply(0), m_expectedCommandClassId(_expectedCommandClassId), m_length(4), m_targetNodeId(_targetNodeId), m_sendAttempts(0), m_maxSendAttempts( MAX_TRIES), m_instance(1), m_endPoint(0), m_flags(0), m_encrypted(false), m_noncerecvd(false), m_homeId(0), m_resendDuetoCANorNAK(false)
5657
{
@@ -102,6 +103,19 @@ namespace OpenZWave
102103
}
103104
}
104105

106+
//-----------------------------------------------------------------------------
107+
// <Msg::SetSupervision>
108+
// Encapsulate the data inside a Supervision message
109+
//-----------------------------------------------------------------------------
110+
void Msg::SetSupervision(uint8 _supervision_session_id)
111+
{
112+
if (_supervision_session_id != Internal::CC::Supervision::StaticNoSessionId())
113+
{
114+
m_supervision_session_id = _supervision_session_id;
115+
m_flags |= m_Supervision;
116+
}
117+
}
118+
105119
//-----------------------------------------------------------------------------
106120
// <Msg::Append>
107121
// Add a byte to the message
@@ -135,6 +149,12 @@ namespace OpenZWave
135149
return;
136150
}
137151

152+
// Deal with Supervision encapsulation
153+
if ((m_flags & m_Supervision) != 0)
154+
{
155+
SupervisionEncap();
156+
}
157+
138158
// Deal with Multi-Channel/Instance encapsulation
139159
if ((m_flags & (m_MultiChannel | m_MultiInstance)) != 0)
140160
{
@@ -280,6 +300,33 @@ namespace OpenZWave
280300
}
281301
}
282302

303+
//-----------------------------------------------------------------------------
304+
// <Msg::SupervisionEncap>
305+
// Encapsulate the data inside a Supervision message
306+
//-----------------------------------------------------------------------------
307+
void Msg::SupervisionEncap()
308+
{
309+
char str[256];
310+
if (m_buffer[3] != FUNC_ID_ZW_SEND_DATA)
311+
{
312+
return;
313+
}
314+
315+
for (uint32 i = m_length - 1; i >= 6; --i)
316+
{
317+
m_buffer[i + 4] = m_buffer[i];
318+
}
319+
m_buffer[6] = Internal::CC::Supervision::StaticGetCommandClassId();
320+
m_buffer[7] = Internal::CC::Supervision::SupervisionCmd_Get;
321+
m_buffer[8] = Internal::CC::Supervision::SupervisionMoreStatusUpdates_MoreReports | m_supervision_session_id;
322+
m_buffer[9] = m_buffer[5];
323+
m_buffer[5] += 4;
324+
m_length += 4;
325+
326+
snprintf(str, sizeof(str), "Supervisioned (session=%d): %s", m_supervision_session_id, m_logText.c_str());
327+
m_logText = str;
328+
}
329+
283330
//-----------------------------------------------------------------------------
284331
// <Node::GetDriver>
285332
// Get a pointer to our driver

cpp/src/Msg.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ namespace OpenZWave
5454
{
5555
m_MultiChannel = 0x01, // Indicate MultiChannel encapsulation
5656
m_MultiInstance = 0x02, // Indicate MultiInstance encapsulation
57+
m_Supervision = 0x04, // Indicate Supervision encapsulation
5758
};
5859

5960
Msg(string const& _logtext, uint8 _targetNodeId, uint8 const _msgType, uint8 const _function, bool const _bCallbackRequired, bool const _bReplyRequired = true, uint8 const _expectedReply = 0, uint8 const _expectedCommandClassId = 0);
@@ -62,6 +63,7 @@ namespace OpenZWave
6263
}
6364

6465
void SetInstance(OpenZWave::Internal::CC::CommandClass * _cc, uint8 const _instance); // Used to enable wrapping with MultiInstance/MultiChannel during finalize.
66+
void SetSupervision(uint8 _session_id);
6567

6668
void Append(uint8 const _data);
6769
void AppendArray(const uint8* const _data, const uint8 _length);
@@ -215,7 +217,7 @@ namespace OpenZWave
215217
{
216218
m_homeId = homeId;
217219
}
218-
void setResendDuetoCANorNAK()
220+
void setResendDuetoCANorNAK()
219221
{
220222
m_resendDuetoCANorNAK = true;
221223
}
@@ -231,6 +233,7 @@ namespace OpenZWave
231233
private:
232234

233235
void MultiEncap(); // Encapsulate the data inside a MultiInstance/Multicommand message
236+
void SupervisionEncap(); // Encapsulate the data inside a Supervision message
234237
string m_logText;
235238
bool m_bFinal;
236239
bool m_bCallbackRequired;
@@ -249,6 +252,7 @@ namespace OpenZWave
249252
uint8 m_instance;
250253
uint8 m_endPoint; // Endpoint to use if the message must be wrapped in a multiInstance or multiChannel command class
251254
uint8 m_flags;
255+
uint8 m_supervision_session_id;
252256

253257
bool m_encrypted;
254258
bool m_noncerecvd;

cpp/src/Node.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include "command_classes/NodeNaming.h"
5959
#include "command_classes/NoOperation.h"
6060
#include "command_classes/Version.h"
61+
#include "command_classes/Supervision.h"
6162
#include "command_classes/SwitchAll.h"
6263
#include "command_classes/ZWavePlusInfo.h"
6364
#include "command_classes/DeviceResetLocally.h"
@@ -4049,3 +4050,35 @@ void Node::WriteMetaDataXML(TiXmlElement *mdElement)
40494050
mdElement->LinkEndChild(cl);
40504051
}
40514052
}
4053+
4054+
//-----------------------------------------------------------------------------
4055+
// <Node::CreateSupervisionSession>
4056+
// Generate a new session id for Supervision encapsulation, if supported
4057+
//-----------------------------------------------------------------------------
4058+
uint8 Node::CreateSupervisionSession(uint8 _command_class_id, uint8 _index)
4059+
{
4060+
if (Internal::CC::CommandClass* cc = GetCommandClass(Internal::CC::Supervision::StaticGetCommandClassId()))
4061+
{
4062+
return cc->CreateSupervisionSession(_command_class_id, _index);
4063+
}
4064+
else
4065+
{
4066+
return Internal::CC::Supervision::StaticNoSessionId();
4067+
}
4068+
}
4069+
4070+
//-----------------------------------------------------------------------------
4071+
// <Node::GetSupervisionIndex>
4072+
// Get the index used by a session
4073+
//-----------------------------------------------------------------------------
4074+
uint32 Node::GetSupervisionIndex(uint8 _session_id)
4075+
{
4076+
if (Internal::CC::CommandClass* cc = GetCommandClass(Internal::CC::Supervision::StaticGetCommandClassId()))
4077+
{
4078+
return cc->GetSupervisionIndex(_session_id);
4079+
}
4080+
else
4081+
{
4082+
return Internal::CC::Supervision::StaticNoIndex();
4083+
}
4084+
}

cpp/src/Node.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,10 @@ namespace OpenZWave
911911
void WriteMetaDataXML(TiXmlElement*);
912912
map<MetaDataFields, string> m_metadata;
913913
map<uint32_t, ChangeLogEntry> m_changeLog;
914+
915+
public:
916+
uint8 CreateSupervisionSession(uint8 _command_class_id, uint8 _index);
917+
uint32 GetSupervisionIndex(uint8 _session_id);
914918
};
915919

916920
} //namespace OpenZWave

cpp/src/command_classes/CommandClass.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ namespace OpenZWave
149149
virtual bool supportsMultiInstance() {
150150
return true;
151151
}
152+
virtual uint8 CreateSupervisionSession(uint8 _command_class_id, uint8 _index) {
153+
return 0;
154+
}
155+
virtual uint32 GetSupervisionIndex(uint8 _session_id) {
156+
return 0;
157+
}
158+
virtual void SupervisionSessionSuccess(uint8 _session_id, uint32 const _instance) {};
152159

153160
void SetInstances(uint8 const _instances);
154161
void SetInstance(uint8 const _endPoint);

cpp/src/command_classes/CommandClasses.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
#include "command_classes/SensorBinary.h"
7171
#include "command_classes/SensorMultilevel.h"
7272
#include "command_classes/SoundSwitch.h"
73+
#include "command_classes/Supervision.h"
7374
#include "command_classes/SwitchAll.h"
7475
#include "command_classes/SwitchBinary.h"
7576
#include "command_classes/SwitchMultilevel.h"
@@ -226,6 +227,7 @@ namespace OpenZWave
226227
cc.Register(SensorBinary::StaticGetCommandClassId(), SensorBinary::StaticGetCommandClassName(), SensorBinary::Create);
227228
cc.Register(SensorMultilevel::StaticGetCommandClassId(), SensorMultilevel::StaticGetCommandClassName(), SensorMultilevel::Create);
228229
cc.Register(SoundSwitch::StaticGetCommandClassId(), SoundSwitch::StaticGetCommandClassName(), SoundSwitch::Create);
230+
cc.Register(Supervision::StaticGetCommandClassId(), Supervision::StaticGetCommandClassName(), Supervision::Create);
229231
cc.Register(SwitchAll::StaticGetCommandClassId(), SwitchAll::StaticGetCommandClassName(), SwitchAll::Create);
230232
cc.Register(SwitchBinary::StaticGetCommandClassId(), SwitchBinary::StaticGetCommandClassName(), SwitchBinary::Create);
231233
cc.Register(SwitchMultilevel::StaticGetCommandClassId(), SwitchMultilevel::StaticGetCommandClassName(), SwitchMultilevel::Create);
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
//-----------------------------------------------------------------------------
2+
//
3+
// Supervision.h
4+
//
5+
// Implementation of the Z-Wave COMMAND_CLASS_SUPERVISION
6+
//
7+
// Copyright (c) 2020 Mark Ruys <mark@paracas.nl>
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/Supervision.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/Value.h"
37+
38+
namespace OpenZWave
39+
{
40+
namespace Internal
41+
{
42+
namespace CC
43+
{
44+
uint8 Supervision::CreateSupervisionSession(uint8 _command_class_id, uint8 _index)
45+
{
46+
m_last_session_id++;
47+
m_last_session_id &= 0x3f;
48+
49+
if (m_sessions.size() >= 6)
50+
{
51+
// Clean up oldest session, we support max 6 simultaneous sessions per node
52+
m_sessions.pop_front();
53+
}
54+
55+
m_sessions.push_back({
56+
.session_id = m_last_session_id,
57+
.command_class_id = _command_class_id,
58+
.index = _index
59+
});
60+
61+
return m_last_session_id;
62+
}
63+
64+
uint32 Supervision::GetSupervisionIndex(uint8 _session_id)
65+
{
66+
for (auto it = m_sessions.cbegin(); it != m_sessions.cend(); ++it)
67+
{
68+
if (it->session_id == _session_id)
69+
{
70+
return it->index;
71+
}
72+
}
73+
74+
return StaticNoIndex();
75+
}
76+
77+
//-----------------------------------------------------------------------------
78+
// <Supervision::HandleSupervisionReport>
79+
// Handle a supervision report message from the Z-Wave network
80+
//-----------------------------------------------------------------------------
81+
void Supervision::HandleSupervisionReport(uint8 const* _data, uint32 const _length, uint32 const _instance)
82+
{
83+
if (Node* node = GetNodeUnsafe())
84+
{
85+
if (_length >= 4)
86+
{
87+
uint8 more_status_updates = _data[1] >> 7;
88+
uint8 session_id = _data[1] & 0x3f;
89+
uint8 status = _data[2];
90+
int duration = _data[3];
91+
92+
const char *status_identifier;
93+
switch (status) {
94+
case 0x00: status_identifier = "NO_SUPPORT"; break;
95+
case 0x01: status_identifier = "WORKING"; break;
96+
case 0x02: status_identifier = "FAIL"; break;
97+
case 0xff: status_identifier = "SUCCESS"; break;
98+
default: status_identifier = "UNKNOWN"; break;
99+
}
100+
101+
for (auto it = m_sessions.cbegin(); it != m_sessions.cend(); ++it)
102+
{
103+
if (it->session_id == session_id)
104+
{
105+
if (CommandClass* pCommandClass = node->GetCommandClass(it->command_class_id))
106+
{
107+
Log::Write(LogLevel_Info, GetNodeId(), "Received SupervisionReport: session %d, %s index %d, status %s, duration %d sec, more status updates %d",
108+
session_id,
109+
pCommandClass->GetCommandClassName().c_str(), it->index,
110+
status_identifier, decodeDuration(duration), more_status_updates);
111+
112+
if (status == SupervisionStatus::SupervisionStatus_Success)
113+
{
114+
pCommandClass->SupervisionSessionSuccess(session_id, _instance);
115+
}
116+
}
117+
else
118+
{
119+
Log::Write(LogLevel_Warning, GetNodeId(), "Received SupervisionReport for unknown CC %d", it->command_class_id);
120+
}
121+
122+
if (more_status_updates == 0)
123+
{
124+
m_sessions.erase(it);
125+
}
126+
127+
return;
128+
}
129+
}
130+
131+
Log::Write(LogLevel_Warning, GetNodeId(), "Received SupervisionReport: unknown session %d, status %s, duration %d sec, more status updates %d",
132+
session_id,
133+
status_identifier, decodeDuration(duration), more_status_updates);
134+
}
135+
}
136+
}
137+
138+
bool Supervision::HandleIncomingMsg(uint8 const* _data, uint32 const _length, uint32 const _instance)
139+
{
140+
return HandleMsg(_data, _length, _instance);
141+
}
142+
143+
//-----------------------------------------------------------------------------
144+
// <Supervision::HandleMsg>
145+
// Handle a message from the Z-Wave network
146+
//-----------------------------------------------------------------------------
147+
bool Supervision::HandleMsg(uint8 const* _data, uint32 const _length, uint32 const _instance) // = 1
148+
{
149+
bool handled = false;
150+
Node* node = GetNodeUnsafe();
151+
if (node != NULL)
152+
{
153+
handled = true;
154+
switch ((SupervisionCmd) _data[0])
155+
{
156+
case SupervisionCmd_Report:
157+
{
158+
HandleSupervisionReport(_data, _length, _instance);
159+
break;
160+
}
161+
default:
162+
{
163+
handled = false;
164+
break;
165+
}
166+
}
167+
}
168+
169+
return handled;
170+
}
171+
} // namespace CC
172+
} // namespace Internal
173+
} // namespace OpenZWave
174+

0 commit comments

Comments
 (0)