@@ -20,22 +20,31 @@ pub struct ShortDevice {
2020
2121#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
2222pub enum AttributeType {
23- UInt8 ,
2423 Bool ,
24+ String ,
25+ UInt8 ,
26+ UInt16 ,
27+ UInt32 ,
2528}
2629
27- #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
30+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
2831pub enum AttributeValue {
2932 NoValue ,
30- UInt8 ( u8 ) ,
3133 Bool ( bool ) ,
34+ String ( String ) ,
35+ UInt8 ( u8 ) ,
36+ UInt16 ( u16 ) ,
37+ UInt32 ( u32 ) ,
3238}
3339
3440impl AttributeType {
3541 pub fn parse ( & self , s : & str ) -> Result < AttributeValue , Box < dyn Error > > {
3642 let payload_str = s. trim ( ) ;
3743 Ok ( match self {
3844 AttributeType :: UInt8 => AttributeValue :: UInt8 ( payload_str. parse :: < u8 > ( ) ?) ,
45+ AttributeType :: UInt16 => AttributeValue :: UInt16 ( payload_str. parse :: < u16 > ( ) ?) ,
46+ AttributeType :: UInt32 => AttributeValue :: UInt32 ( payload_str. parse :: < u32 > ( ) ?) ,
47+ AttributeType :: String => AttributeValue :: String ( payload_str. to_string ( ) ) ,
3948 AttributeType :: Bool => {
4049 AttributeValue :: Bool ( match payload_str. to_ascii_lowercase ( ) . as_str ( ) {
4150 "true" | "1" | "yes" | "on" => true ,
@@ -141,7 +150,7 @@ lazy_static! {
141150 static ref ATTRIBUTE_REGEX_STR : String = r"\s*(?P<id>\d+)\s*\|\s*(?P<description>[^\|]+)\s*\|\s*(?P<type>[^ ]+)\s*\|\s*(?P<mode>[^ ]+)\s*\|\s*(?P<get>[^ ]*)\s*\| *(?P<set>[^\n ]*)" . to_owned( ) ;
142151 static ref LONG_DEVICE_REGEX : Regex = Regex :: new( & ( (
143152 "" . to_owned( ) +
144- r"(?ms)Gang ID: (?P<gang_id>(0x)?[0-9a-fA-F]+)\n" +
153+ r"(?ms)(?: Gang ID: (?P<gang_id>(0x)?[0-9a-fA-F]+)\n)? " +
145154 // r"(?:[^\n]+\n)*" +
146155 r"(?:Generic/Specific device types: (?P<generic_device_type>(0x)?[0-9a-fA-F]+)/(?P<specific_device_type>(0x)?[0-9a-fA-F]+)\n)?" +
147156 // r"(?:[^\n]+\n)*" +
@@ -180,11 +189,14 @@ fn parse_attr_value(t: AttributeType, v: &str) -> Result<AttributeValue, Box<dyn
180189 "" => AttributeValue :: NoValue ,
181190 v => match t {
182191 AttributeType :: UInt8 => AttributeValue :: UInt8 ( v. parse ( ) ?) ,
192+ AttributeType :: UInt16 => AttributeValue :: UInt16 ( v. parse ( ) ?) ,
193+ AttributeType :: UInt32 => AttributeValue :: UInt32 ( v. parse ( ) ?) ,
183194 AttributeType :: Bool => AttributeValue :: Bool ( match v {
184195 "TRUE" => true ,
185196 "FALSE" => false ,
186197 _ => bail ! ( "Bad attribute value: {}" , v) ,
187198 } ) ,
199+ AttributeType :: String => AttributeValue :: String ( v. to_string ( ) ) ,
188200 } ,
189201 } )
190202}
@@ -253,7 +265,10 @@ impl DeviceController for AprontestController {
253265 . map ( |m| -> Result < DeviceAttribute , Box < dyn Error > > {
254266 let attribute_type = match m. name ( "type" ) . unwrap ( ) . as_str ( ) {
255267 "UINT8" => AttributeType :: UInt8 ,
268+ "UINT16" => AttributeType :: UInt16 ,
269+ "UINT32" => AttributeType :: UInt32 ,
256270 "BOOL" => AttributeType :: Bool ,
271+ "STRING" => AttributeType :: String ,
257272 _ => bail ! ( "Bad attribute type: {}" , m. name( "type" ) . unwrap( ) . as_str( ) ) ,
258273 } ;
259274 Ok ( DeviceAttribute {
@@ -285,7 +300,10 @@ impl DeviceController for AprontestController {
285300 let value = match value {
286301 AttributeValue :: NoValue => bail ! ( "Invalid attribute value: none" ) ,
287302 AttributeValue :: UInt8 ( v) => format ! ( "{}" , v) ,
303+ AttributeValue :: UInt16 ( v) => format ! ( "{}" , v) ,
304+ AttributeValue :: UInt32 ( v) => format ! ( "{}" , v) ,
288305 AttributeValue :: Bool ( v) => if * v { "TRUE" } else { "FALSE" } . to_string ( ) ,
306+ AttributeValue :: String ( v) => v. clone ( ) ,
289307 } ;
290308 ( self . runner ) ( & [
291309 "aprontest" ,
@@ -340,29 +358,33 @@ impl DeviceController for FakeController {
340358 attribute_type: AttributeType :: UInt8 ,
341359 supports_write: true ,
342360 supports_read: true ,
343- current_value: * self
361+ current_value: self
344362 . attr_values
345363 . get( & ( master_id, 1 as AttributeId ) )
346- . unwrap_or( & AttributeValue :: UInt8 ( 0 ) ) ,
347- setting_value: * self
364+ . unwrap_or( & AttributeValue :: UInt8 ( 0 ) )
365+ . clone( ) ,
366+ setting_value: self
348367 . attr_values
349368 . get( & ( master_id, 1 as AttributeId ) )
350- . unwrap_or( & AttributeValue :: UInt8 ( 0 ) ) ,
369+ . unwrap_or( & AttributeValue :: UInt8 ( 0 ) )
370+ . clone( ) ,
351371 } ,
352372 DeviceAttribute {
353373 id: 3 ,
354374 description: "Level" . to_string( ) ,
355375 attribute_type: AttributeType :: UInt8 ,
356376 supports_write: true ,
357377 supports_read: true ,
358- current_value: * self
378+ current_value: self
359379 . attr_values
360380 . get( & ( master_id, 3 as AttributeId ) )
361- . unwrap_or( & AttributeValue :: UInt8 ( 0 ) ) ,
362- setting_value: * self
381+ . unwrap_or( & AttributeValue :: UInt8 ( 0 ) )
382+ . clone( ) ,
383+ setting_value: self
363384 . attr_values
364385 . get( & ( master_id, 3 as AttributeId ) )
365- . unwrap_or( & AttributeValue :: UInt8 ( 0 ) ) ,
386+ . unwrap_or( & AttributeValue :: UInt8 ( 0 ) )
387+ . clone( ) ,
366388 } ,
367389 DeviceAttribute {
368390 id: 4 ,
@@ -519,4 +541,133 @@ Bedroom Fan
519541 controller. describe( 2 ) . unwrap( )
520542 )
521543 }
544+
545+ const TEST_OLD_LIST_STRING : & str = r###"
546+ Found 4 devices in database...
547+ MASTERID | INTERCONNECT | USERNAME
548+ 1 | ZIGBEE | LV_Lamp1
549+ 2 | ZIGBEE | LV_Lamp2
550+ 3 | ZIGBEE | Fireplace-L
551+ 4 | ZIGBEE | Fireplace-R
552+ "### ;
553+
554+ #[ test]
555+ fn older_list ( ) {
556+ let controller = AprontestController {
557+ runner : |_| Ok ( TEST_OLD_LIST_STRING . to_string ( ) ) ,
558+ } ;
559+
560+ assert_eq ! (
561+ vec![
562+ ShortDevice {
563+ id: 1 ,
564+ name: "LV_Lamp1" . to_string( )
565+ } ,
566+ ShortDevice {
567+ id: 2 ,
568+ name: "LV_Lamp2" . to_string( )
569+ } ,
570+ ShortDevice {
571+ id: 3 ,
572+ name: "Fireplace-L" . to_string( )
573+ } ,
574+ ShortDevice {
575+ id: 4 ,
576+ name: "Fireplace-R" . to_string( )
577+ }
578+ ] ,
579+ controller. list( ) . unwrap( )
580+ )
581+ }
582+
583+ const TEST_OLD_DESCRIBE_STRING : & str = r###"
584+ Device has 2 attributes...
585+ LV_Lamp1
586+ ATTRIBUTE | DESCRIPTION | TYPE | MODE | GET | SET
587+ 1 | On_Off | STRING | R/W | ON | ON
588+ 2 | Level | UINT8 | R/W | 0 | 0
589+ "### ;
590+
591+ #[ test]
592+ fn old_describe ( ) {
593+ let controller = AprontestController {
594+ runner : |_| Ok ( TEST_OLD_DESCRIBE_STRING . to_string ( ) ) ,
595+ } ;
596+
597+ assert_eq ! (
598+ LongDevice {
599+ gang_id: None ,
600+ generic_device_type: None ,
601+ specific_device_type: None ,
602+ manufacturer_id: None ,
603+ product_type: None ,
604+ product_number: None ,
605+ id: 2 ,
606+ status: "" . to_string( ) ,
607+ name: "LV_Lamp1" . to_string( ) ,
608+ attributes: vec![
609+ DeviceAttribute {
610+ id: 1 ,
611+ description: "On_Off" . to_string( ) ,
612+ attribute_type: AttributeType :: String ,
613+ supports_write: true ,
614+ supports_read: true ,
615+ current_value: AttributeValue :: String ( "ON" . to_string( ) ) ,
616+ setting_value: AttributeValue :: String ( "ON" . to_string( ) ) ,
617+ } ,
618+ DeviceAttribute {
619+ id: 2 ,
620+ description: "Level" . to_string( ) ,
621+ attribute_type: AttributeType :: UInt8 ,
622+ supports_write: true ,
623+ supports_read: true ,
624+ current_value: AttributeValue :: UInt8 ( 0 ) ,
625+ setting_value: AttributeValue :: UInt8 ( 0 ) ,
626+ } ,
627+ ]
628+ } ,
629+ controller. describe( 2 ) . unwrap( )
630+ )
631+ }
632+
633+ const OTHER_TYPES_DESCRIBE : & str = r###"
634+ Gang ID: 0x7ce8f9f9
635+ Manufacturer ID: 0x10dc, Product Number: 0xdfbf
636+ Device is ONLINE, 0 failed tx attempts, 4 seconds since last msg rx'ed, polling period 0 seconds
637+ Device has 14 attributes...
638+ New HA Dimmable Light
639+ ATTRIBUTE | DESCRIPTION | TYPE | MODE | GET | SET
640+ 1 | On_Off | STRING | R/W | OFF | OFF
641+ 2 | Level | UINT8 | R/W | 254 |
642+ 4 | NameSupport | UINT8 | R | 0 |
643+ 61440 | ZCLVersion | UINT8 | R | 1 |
644+ 61441 | ApplicationVersion | UINT8 | R | 2 |
645+ 61442 | StackVersion | UINT8 | R | 2 |
646+ 61443 | HWVersion | UINT8 | R | 1 |
647+ 61444 | ManufacturerName | STRING | R | GE |
648+ 61445 | ModelIdentifier | STRING | R | SoftWhite |
649+ 61446 | DateCode | STRING | R | 20150515 |
650+ 61447 | PowerSource | UINT8 | R | 1 |
651+ 258048 | IdentifyTime | UINT16 | R/W | 0 |
652+ 1699842 | ZB_CurrentFileVersion | UINT32 | R | 33554952 |
653+ 4294901760 | WK_TransitionTime | UINT16 | R/W | |
654+ "### ;
655+
656+ #[ test]
657+ fn types_describe ( ) {
658+ let controller = AprontestController {
659+ runner : |_| Ok ( OTHER_TYPES_DESCRIBE . to_string ( ) ) ,
660+ } ;
661+
662+ let result = controller. describe ( 2 ) . unwrap ( ) ;
663+ assert_eq ! ( 14 , result. attributes. len( ) ) ;
664+ assert_eq ! (
665+ AttributeType :: UInt32 ,
666+ result. attributes[ result. attributes. len( ) - 2 ] . attribute_type
667+ ) ;
668+ assert_eq ! (
669+ AttributeValue :: UInt32 ( 33554952 ) ,
670+ result. attributes[ result. attributes. len( ) - 2 ] . current_value
671+ ) ;
672+ }
522673}
0 commit comments