1 //-----------------------------------------------------------------------------
2 //
3 //	SwitchMultilevel.cpp
4 //
5 //	Implementation of the Z-Wave COMMAND_CLASS_SWITCH_MULTILEVEL
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 //-----------------------------------------------------------------------------
27 
28 #include "command_classes/CommandClasses.h"
29 #include "command_classes/SwitchMultilevel.h"
30 #include "command_classes/WakeUp.h"
31 #include "Defs.h"
32 #include "Msg.h"
33 #include "Driver.h"
34 #include "Node.h"
35 #include "platform/Log.h"
36 
37 #include "value_classes/ValueBool.h"
38 #include "value_classes/ValueButton.h"
39 #include "value_classes/ValueByte.h"
40 
41 using namespace OpenZWave;
42 
43 enum SwitchMultilevelCmd
44 {
45 	SwitchMultilevelCmd_Set						= 0x01,
46 	SwitchMultilevelCmd_Get						= 0x02,
47 	SwitchMultilevelCmd_Report					= 0x03,
48 	SwitchMultilevelCmd_StartLevelChange				= 0x04,
49 	SwitchMultilevelCmd_StopLevelChange				= 0x05,
50 	SwitchMultilevelCmd_SupportedGet				= 0x06,
51 	SwitchMultilevelCmd_SupportedReport				= 0x07
52 };
53 
54 enum
55 {
56 	SwitchMultilevelIndex_Level = 0,
57 	SwitchMultilevelIndex_Bright,
58 	SwitchMultilevelIndex_Dim,
59 	SwitchMultilevelIndex_IgnoreStartLevel,
60 	SwitchMultilevelIndex_StartLevel,
61 	SwitchMultilevelIndex_Duration,
62 	SwitchMultilevelIndex_Step,
63 	SwitchMultilevelIndex_Inc,
64 	SwitchMultilevelIndex_Dec
65 };
66 
67 static uint8 c_directionParams[] =
68 {
69 	0x00,
70 	0x40,
71 	0x00,
72 	0x40
73 };
74 
75 static char const* c_directionDebugLabels[] =
76 {
77 	"Up",
78 	"Down",
79 	"Inc",
80 	"Dec"
81 };
82 
83 static char const* c_switchLabelsPos[] =
84 {
85 	"Undefined",
86 	"On",
87 	"Up",
88 	"Open",
89 	"Clockwise",
90 	"Right",
91 	"Forward",
92 	"Push"
93 };
94 
95 static char const* c_switchLabelsNeg[] =
96 {
97 	"Undefined",
98 	"Off",
99 	"Down",
100 	"Close",
101 	"Counter-Clockwise",
102 	"Left",
103 	"Reverse",
104 	"Pull"
105 };
106 
107 //-----------------------------------------------------------------------------
108 // <SwitchMultilevel::RequestState>
109 // Request current state from the device
110 //-----------------------------------------------------------------------------
RequestState(uint32 const _requestFlags,uint8 const _instance,Driver::MsgQueue const _queue)111 bool SwitchMultilevel::RequestState
112 (
113 	uint32 const _requestFlags,
114 	uint8 const _instance,
115 	Driver::MsgQueue const _queue
116 )
117 {
118 	if( _requestFlags & RequestFlag_Dynamic )
119 	{
120 		return RequestValue( _requestFlags, 0, _instance, _queue );
121 	}
122 
123 	return false;
124 }
125 
126 //-----------------------------------------------------------------------------
127 // <SwitchMultilevel::RequestValue>
128 // Request current value from the device
129 //-----------------------------------------------------------------------------
RequestValue(uint32 const _requestFlags,uint8 const _index,uint8 const _instance,Driver::MsgQueue const _queue)130 bool SwitchMultilevel::RequestValue
131 (
132 	uint32 const _requestFlags,
133 	uint8 const _index,
134 	uint8 const _instance,
135 	Driver::MsgQueue const _queue
136 )
137 {
138 	if( _index == SwitchMultilevelIndex_Level )
139 	{
140 		if ( IsGetSupported() )
141 		{
142 			Msg* msg = new Msg( "SwitchMultilevelCmd_Get", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
143 			msg->SetInstance( this, _instance );
144 			msg->Append( GetNodeId() );
145 			msg->Append( 2 );
146 			msg->Append( GetCommandClassId() );
147 			msg->Append( SwitchMultilevelCmd_Get );
148 			msg->Append( GetDriver()->GetTransmitOptions() );
149 			GetDriver()->SendMsg( msg, _queue );
150 			return true;
151 		} else {
152 			Log::Write(  LogLevel_Info, GetNodeId(), "SwitchMultilevelCmd_Get Not Supported on this node");
153 		}
154 	}
155 	return false;
156 }
157 
158 //-----------------------------------------------------------------------------
159 // <SwitchMultilevel::HandleMsg>
160 // Handle a message from the Z-Wave network
161 //-----------------------------------------------------------------------------
HandleMsg(uint8 const * _data,uint32 const _length,uint32 const _instance)162 bool SwitchMultilevel::HandleMsg
163 (
164 	uint8 const* _data,
165 	uint32 const _length,
166 	uint32 const _instance	// = 1
167 )
168 {
169 	if( SwitchMultilevelCmd_Report == (SwitchMultilevelCmd)_data[0] )
170 	{
171 		Log::Write( LogLevel_Info, GetNodeId(), "Received SwitchMultiLevel report: level=%d", _data[1] );
172 
173 		if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, SwitchMultilevelIndex_Level ) ) )
174 		{
175 			value->OnValueRefreshed( _data[1] );
176 			value->Release();
177 		}
178 		return true;
179 	}
180 
181 	if( SwitchMultilevelCmd_SupportedReport == (SwitchMultilevelCmd)_data[0] )
182 	{
183 		uint8 switchType1 = _data[1] & 0x1f;
184 		uint8 switchType2 = _data[2] & 0x1f;
185 		uint8 switchtype1label = switchType1;
186 		uint8 switchtype2label = switchType2;
187 		if (switchtype1label > 7) /* size of c_switchLabelsPos, c_switchLabelsNeg */
188 		{
189 			Log::Write (LogLevel_Warning, GetNodeId(), "switchtype1label Value was greater than range. Setting to Invalid");
190 			switchtype1label = 0;
191 		}
192 		if (switchtype2label > 7) /* sizeof c_switchLabelsPos, c_switchLabelsNeg */
193 		{
194 			Log::Write (LogLevel_Warning, GetNodeId(), "switchtype2label Value was greater than range. Setting to Invalid");
195 			switchtype2label = 0;
196 		}
197 
198 
199 		Log::Write( LogLevel_Info, GetNodeId(), "Received SwitchMultiLevel supported report: Switch1=%s/%s, Switch2=%s/%s", c_switchLabelsPos[switchtype1label], c_switchLabelsNeg[switchtype1label], c_switchLabelsPos[switchtype2label], c_switchLabelsNeg[switchtype2label] );
200 		ClearStaticRequest( StaticRequest_Version );
201 
202 		// Set the labels on the values
203 		ValueButton* button;
204 
205 		if( switchType1 )
206 		{
207 			if( NULL != ( button = static_cast<ValueButton*>( GetValue( _instance, SwitchMultilevelIndex_Bright ) ) ) )
208 			{
209 				button->SetLabel( c_switchLabelsPos[switchtype1label] );
210 				button->Release();
211 			}
212 			if( NULL != ( button = static_cast<ValueButton*>( GetValue( _instance, SwitchMultilevelIndex_Dim ) ) ) )
213 			{
214 				button->SetLabel( c_switchLabelsNeg[switchtype1label] );
215 				button->Release();
216 			}
217 		}
218 
219 		if( switchType2 )
220 		{
221 			if( NULL != ( button = static_cast<ValueButton*>( GetValue( _instance, SwitchMultilevelIndex_Inc ) ) ) )
222 			{
223 				button->SetLabel( c_switchLabelsPos[switchtype2label] );
224 				button->Release();
225 			}
226 			if( NULL != ( button = static_cast<ValueButton*>( GetValue( _instance, SwitchMultilevelIndex_Dec ) ) ) )
227 			{
228 				button->SetLabel( c_switchLabelsNeg[switchtype2label] );
229 				button->Release();
230 			}
231 		}
232 		return true;
233 	}
234 
235 	return false;
236 }
237 
238 //-----------------------------------------------------------------------------
239 // <SwitchMultilevel::SetVersion>
240 // Set the command class version
241 //-----------------------------------------------------------------------------
SetVersion(uint8 const _version)242 void SwitchMultilevel::SetVersion
243 (
244 	uint8 const _version
245 )
246 {
247 	CommandClass::SetVersion( _version );
248 
249 	if( _version == 3 )
250 	{
251 		// Request the supported switch types
252 		Msg* msg = new Msg( "SwitchMultilevelCmd_SupportedGet", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true, true, FUNC_ID_APPLICATION_COMMAND_HANDLER, GetCommandClassId() );
253 		msg->Append( GetNodeId() );
254 		msg->Append( 2 );
255 		msg->Append( GetCommandClassId() );
256 		msg->Append( SwitchMultilevelCmd_SupportedGet );
257 		msg->Append( GetDriver()->GetTransmitOptions() );
258 		GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
259 
260 		// Set the request flag again - it will be cleared when we get a
261 		// response to the SwitchMultilevelCmd_SupportedGet message.
262 		SetStaticRequest( StaticRequest_Version );
263 	}
264 }
265 
266 //-----------------------------------------------------------------------------
267 // <SwitchMultilevel::SetValue>
268 // Set the level on a device
269 //-----------------------------------------------------------------------------
SetValue(Value const & _value)270 bool SwitchMultilevel::SetValue
271 (
272 	Value const& _value
273 )
274 {
275 	bool res = false;
276 	uint8 instance = _value.GetID().GetInstance();
277 
278 	switch( _value.GetID().GetIndex() )
279 	{
280 		case SwitchMultilevelIndex_Level:
281 		{
282 			// Level
283 			if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, SwitchMultilevelIndex_Level ) ) )
284 			{
285 				res = SetLevel( instance, (static_cast<ValueByte const*>(&_value))->GetValue() );
286 				value->Release();
287 			}
288 			break;
289 		}
290 		case SwitchMultilevelIndex_Bright:
291 		{
292 			// Bright
293 			if( ValueButton* button = static_cast<ValueButton*>( GetValue( instance, SwitchMultilevelIndex_Bright ) ) )
294 			{
295 				if( button->IsPressed() )
296 				{
297 					res = StartLevelChange( instance, SwitchMultilevelDirection_Up );
298 				}
299 				else
300 				{
301 					res = StopLevelChange( instance );
302 				}
303 				button->Release();
304 			}
305 			break;
306 		}
307 		case SwitchMultilevelIndex_Dim:
308 		{
309 			// Dim
310 			if( ValueButton* button = static_cast<ValueButton*>( GetValue( instance, SwitchMultilevelIndex_Dim ) ) )
311 			{
312 				if( button->IsPressed() )
313 				{
314 					res = StartLevelChange( instance, SwitchMultilevelDirection_Down );
315 				}
316 				else
317 				{
318 					res = StopLevelChange( instance );
319 				}
320 				button->Release();
321 			}
322 			break;
323 		}
324 		case SwitchMultilevelIndex_IgnoreStartLevel:
325 		{
326 			if( ValueBool* value = static_cast<ValueBool*>( GetValue( instance, SwitchMultilevelIndex_IgnoreStartLevel ) ) )
327 			{
328 				value->OnValueRefreshed( (static_cast<ValueBool const*>( &_value))->GetValue() );
329 				value->Release();
330 			}
331 			res = true;
332 			break;
333 		}
334 		case SwitchMultilevelIndex_StartLevel:
335 		{
336 			if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, SwitchMultilevelIndex_StartLevel ) ) )
337 			{
338 				value->OnValueRefreshed( (static_cast<ValueByte const*>( &_value))->GetValue() );
339 				value->Release();
340 			}
341 			res = true;
342 			break;
343 		}
344 		case SwitchMultilevelIndex_Duration:
345 		{
346 			if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, SwitchMultilevelIndex_Duration ) ) )
347 			{
348 				value->OnValueRefreshed( (static_cast<ValueByte const*>( &_value))->GetValue() );
349 				value->Release();
350 			}
351 			res = true;
352 			break;
353 		}
354 		case SwitchMultilevelIndex_Step:
355 		{
356 			if( ValueByte* value = static_cast<ValueByte*>( GetValue( instance, SwitchMultilevelIndex_Step ) ) )
357 			{
358 				value->OnValueRefreshed( (static_cast<ValueByte const*>( &_value))->GetValue() );
359 				value->Release();
360 			}
361 			res = true;
362 			break;
363 		}
364 		case SwitchMultilevelIndex_Inc:
365 		{
366 			// Inc
367 			if( ValueButton* button = static_cast<ValueButton*>( GetValue( instance, SwitchMultilevelIndex_Inc ) ) )
368 			{
369 				if( button->IsPressed() )
370 				{
371 					res = StartLevelChange( instance, SwitchMultilevelDirection_Inc );
372 				}
373 				else
374 				{
375 					res = StopLevelChange( instance );
376 				}
377 				button->Release();
378 			}
379 			break;
380 		}
381 		case SwitchMultilevelIndex_Dec:
382 		{
383 			// Dec
384 			if( ValueButton* button = static_cast<ValueButton*>( GetValue( instance, SwitchMultilevelIndex_Dec ) ) )
385 			{
386 				if( button->IsPressed() )
387 				{
388 					res = StartLevelChange( instance, SwitchMultilevelDirection_Dec );
389 				}
390 				else
391 				{
392 					res = StopLevelChange( instance );
393 				}
394 				button->Release();
395 			}
396 			break;
397 		}
398 	}
399 
400 	return res;
401 }
402 
403 //-----------------------------------------------------------------------------
404 // <SwitchMultilevel::SetValueBasic>
405 // Update class values based in BASIC mapping
406 //-----------------------------------------------------------------------------
SetValueBasic(uint8 const _instance,uint8 const _value)407 void SwitchMultilevel::SetValueBasic
408 (
409 	uint8 const _instance,
410 	uint8 const _value
411 )
412 {
413 	// Send a request for new value to synchronize it with the BASIC set/report.
414 	// In case the device is sleeping, we set the value anyway so the BASIC set/report
415 	// stays in sync with it. We must be careful mapping the uint8 BASIC value
416 	// into a class specific value.
417 	// When the device wakes up, the real requested value will be retrieved.
418 	RequestValue( 0, 0, _instance, Driver::MsgQueue_Send );
419 	if( Node* node = GetNodeUnsafe() )
420 	{
421 		if( WakeUp* wakeUp = static_cast<WakeUp*>( node->GetCommandClass( WakeUp::StaticGetCommandClassId() ) ) )
422 		{
423 			if( !wakeUp->IsAwake() )
424 			{
425 				if( ValueByte* value = static_cast<ValueByte*>( GetValue( _instance, SwitchMultilevelIndex_Level ) ) )
426 				{
427 					value->OnValueRefreshed( _value != 0 );
428 					value->Release();
429 				}
430 			}
431 		}
432 	}
433 }
434 
435 //-----------------------------------------------------------------------------
436 // <SwitchMultilevel::SetLevel>
437 // Set a new level for the switch
438 //-----------------------------------------------------------------------------
SetLevel(uint8 const _instance,uint8 const _level)439 bool SwitchMultilevel::SetLevel
440 (
441 	uint8 const _instance,
442 	uint8 const _level
443 )
444 {
445 	Log::Write( LogLevel_Info, GetNodeId(), "SwitchMultilevel::Set - Setting to level %d", _level );
446 	Msg* msg = new Msg( "SwitchMultilevelCmd_Set", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
447 	msg->SetInstance( this, _instance );
448 	msg->Append( GetNodeId() );
449 
450 	if( ValueByte* durationValue = static_cast<ValueByte*>( GetValue( _instance, SwitchMultilevelIndex_Duration ) ) )
451 	{
452 		uint8 duration = durationValue->GetValue();
453 		durationValue->Release();
454 		if( duration == 0xff )
455 		{
456 			Log::Write( LogLevel_Info, GetNodeId(), "  Duration: Default" );
457 		}
458 		else if( duration >= 0x80 )
459 		{
460 			Log::Write( LogLevel_Info, GetNodeId(), "  Duration: %d minutes", duration - 0x7f );
461 		}
462 		else
463 		{
464 			Log::Write( LogLevel_Info, GetNodeId(), "  Duration: %d seconds", duration );
465 		}
466 
467 		msg->Append( 4 );
468 		msg->Append( GetCommandClassId() );
469 		msg->Append( SwitchMultilevelCmd_Set );
470 		msg->Append( _level );
471 		msg->Append( duration );
472 	}
473 	else
474 	{
475 		msg->Append( 3 );
476 		msg->Append( GetCommandClassId() );
477 		msg->Append( SwitchMultilevelCmd_Set );
478 		msg->Append( _level );
479 	}
480 
481 	msg->Append( GetDriver()->GetTransmitOptions() );
482 	GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
483 	return true;
484 }
485 
486 //-----------------------------------------------------------------------------
487 // <SwitchMultilevel::SwitchMultilevelCmd_StartLevelChange>
488 // Start the level changing
489 //-----------------------------------------------------------------------------
StartLevelChange(uint8 const _instance,SwitchMultilevelDirection const _direction)490 bool SwitchMultilevel::StartLevelChange
491 (
492 	uint8 const _instance,
493 	SwitchMultilevelDirection const _direction
494 )
495 {
496 	Log::Write( LogLevel_Info, GetNodeId(), "SwitchMultilevel::StartLevelChange - Starting a level change" );
497 
498 	uint8 length = 4;
499 	if (_direction > 3) /* size of  c_directionParams, c_directionDebugLabels */
500 	{
501 		Log::Write (LogLevel_Warning, GetNodeId(), "_direction Value was greater than range. Dropping");
502 		return false;
503 	}
504 	uint8 direction = c_directionParams[_direction];
505 	Log::Write( LogLevel_Info, GetNodeId(), "  Direction:          %s", c_directionDebugLabels[_direction] );
506 
507 	if( ValueBool* ignoreStartLevel = static_cast<ValueBool*>( GetValue( _instance, SwitchMultilevelIndex_IgnoreStartLevel ) ) )
508 	{
509 		if( ignoreStartLevel->GetValue() )
510 		{
511 			// Set the ignore start level flag
512 			direction |= 0x20;
513 		}
514 		ignoreStartLevel->Release();
515 	}
516 	Log::Write( LogLevel_Info, GetNodeId(), "  Ignore Start Level: %s", (direction & 0x20) ? "True" : "False" );
517 
518 	uint8 startLevel = 0;
519 	if( ValueByte* startLevelValue = static_cast<ValueByte*>( GetValue( _instance, SwitchMultilevelIndex_StartLevel ) ) )
520 	{
521 		startLevel = startLevelValue->GetValue();
522 		startLevelValue->Release();
523 	}
524 	Log::Write( LogLevel_Info, GetNodeId(), "  Start Level:        %d", startLevel );
525 
526 	uint8 duration = 0;
527 	if( ValueByte* durationValue = static_cast<ValueByte*>( GetValue( _instance, SwitchMultilevelIndex_Duration ) ) )
528 	{
529 		length = 5;
530 		duration = durationValue->GetValue();
531 		durationValue->Release();
532 		Log::Write( LogLevel_Info, GetNodeId(), "  Duration:           %d", duration );
533 	}
534 
535 	uint8 step = 0;
536 	if( ( SwitchMultilevelDirection_Inc == _direction ) || ( SwitchMultilevelDirection_Dec == _direction ) )
537 	{
538 		if( ValueByte* stepValue = static_cast<ValueByte*>( GetValue( _instance, SwitchMultilevelIndex_Step ) ) )
539 		{
540 			length = 6;
541 			step = stepValue->GetValue();
542 			stepValue->Release();
543 			Log::Write( LogLevel_Info, GetNodeId(), "  Step Size:          %d", step );
544 		}
545 	}
546 
547 	Msg* msg = new Msg( "SwitchMultilevelCmd_StartLevelChange", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
548 	msg->SetInstance( this, _instance );
549 	msg->Append( GetNodeId() );
550 	msg->Append( length );
551 	msg->Append( GetCommandClassId() );
552 	msg->Append( SwitchMultilevelCmd_StartLevelChange );
553 	if (GetVersion() == 2) {
554 		direction &= 0x60;
555 	} else if (GetVersion() >= 3) {
556 		/* we don't support secondary switch, so we mask that out as well */
557 		direction &= 0xE0;
558 	}
559 
560 	msg->Append( direction );
561 	msg->Append( startLevel );
562 
563 	if( length >= 5 )
564 	{
565 		msg->Append( duration );
566 	}
567 
568 	if( length == 6 )
569 	{
570 		msg->Append( step );
571 	}
572 
573 	msg->Append( GetDriver()->GetTransmitOptions() );
574 	GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
575 	return true;
576 }
577 
578 //-----------------------------------------------------------------------------
579 // <SwitchMultilevel::StopLevelChange>
580 // Stop the level changing
581 //-----------------------------------------------------------------------------
StopLevelChange(uint8 const _instance)582 bool SwitchMultilevel::StopLevelChange
583 (
584 	uint8 const _instance
585 )
586 {
587 	Log::Write( LogLevel_Info, GetNodeId(), "SwitchMultilevel::StopLevelChange - Stopping the level change" );
588 	Msg* msg = new Msg( "SwitchMultilevelCmd_StopLevelChange", GetNodeId(), REQUEST, FUNC_ID_ZW_SEND_DATA, true );
589 	msg->SetInstance( this, _instance );
590 	msg->Append( GetNodeId() );
591 	msg->Append( 2 );
592 	msg->Append( GetCommandClassId() );
593 	msg->Append( SwitchMultilevelCmd_StopLevelChange );
594 	msg->Append( GetDriver()->GetTransmitOptions() );
595 	GetDriver()->SendMsg( msg, Driver::MsgQueue_Send );
596 	return true;
597 }
598 
599 //-----------------------------------------------------------------------------
600 // <SwitchMultilevel::CreateVars>
601 // Create the values managed by this command class
602 //-----------------------------------------------------------------------------
CreateVars(uint8 const _instance)603 void SwitchMultilevel::CreateVars
604 (
605 	uint8 const _instance
606 )
607 {
608 	if( Node* node = GetNodeUnsafe() )
609 	{
610 		switch( GetVersion() )
611 		{
612 			case 3:
613 			{
614 			  	node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, SwitchMultilevelIndex_Step, "Step Size", "", false, false, 0, 0 );
615 				node->CreateValueButton( ValueID::ValueGenre_User, GetCommandClassId(), _instance, SwitchMultilevelIndex_Inc, "Inc", 0 );
616 				node->CreateValueButton( ValueID::ValueGenre_User, GetCommandClassId(), _instance, SwitchMultilevelIndex_Dec, "Dec", 0 );
617 				// Fall through to version 2
618 			}
619 			case 2:
620 			{
621 			  	node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, SwitchMultilevelIndex_Duration, "Dimming Duration", "", false, false, 0xff, 0 );
622 				// Fall through to version 1
623 			}
624 			case 1:
625 			{
626 			  	node->CreateValueByte( ValueID::ValueGenre_User, GetCommandClassId(), _instance, SwitchMultilevelIndex_Level, "Level", "", false, false, 0, 0 );
627 				node->CreateValueButton( ValueID::ValueGenre_User, GetCommandClassId(), _instance, SwitchMultilevelIndex_Bright, "Bright", 0 );
628 				node->CreateValueButton( ValueID::ValueGenre_User, GetCommandClassId(), _instance, SwitchMultilevelIndex_Dim, "Dim", 0 );
629 				node->CreateValueBool( ValueID::ValueGenre_System, GetCommandClassId(), _instance, SwitchMultilevelIndex_IgnoreStartLevel, "Ignore Start Level", "", false, false, true, 0 );
630 				node->CreateValueByte( ValueID::ValueGenre_System, GetCommandClassId(), _instance, SwitchMultilevelIndex_StartLevel, "Start Level", "", false, false, 0, 0 );
631 				break;
632 			}
633 		}
634 	}
635 }
636 
637 
638 
639