1use bacnet_types::enums::{ObjectType, PropertyIdentifier};
8use bacnet_types::error::Error;
9use bacnet_types::primitives::{ObjectIdentifier, PropertyValue, StatusFlags};
10use std::borrow::Cow;
11
12use crate::common::{self, read_common_properties};
13use crate::traits::BACnetObject;
14
15pub struct ElevatorGroupObject {
21 oid: ObjectIdentifier,
22 name: String,
23 description: String,
24 group_id: u64,
26 group_members: Vec<ObjectIdentifier>,
28 group_mode: u32,
30 landing_calls: u64,
32 landing_call_control: u32,
34 status_flags: StatusFlags,
35 out_of_service: bool,
36 reliability: u32,
37}
38
39impl ElevatorGroupObject {
40 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
42 let oid = ObjectIdentifier::new(ObjectType::ELEVATOR_GROUP, instance)?;
43 Ok(Self {
44 oid,
45 name: name.into(),
46 description: String::new(),
47 group_id: 0,
48 group_members: Vec::new(),
49 group_mode: 0, landing_calls: 0,
51 landing_call_control: 0,
52 status_flags: StatusFlags::empty(),
53 out_of_service: false,
54 reliability: 0,
55 })
56 }
57
58 pub fn add_member(&mut self, oid: ObjectIdentifier) {
60 self.group_members.push(oid);
61 }
62}
63
64impl BACnetObject for ElevatorGroupObject {
65 fn object_identifier(&self) -> ObjectIdentifier {
66 self.oid
67 }
68
69 fn object_name(&self) -> &str {
70 &self.name
71 }
72
73 fn read_property(
74 &self,
75 property: PropertyIdentifier,
76 array_index: Option<u32>,
77 ) -> Result<PropertyValue, Error> {
78 if let Some(result) = read_common_properties!(self, property, array_index) {
79 return result;
80 }
81 match property {
82 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
83 ObjectType::ELEVATOR_GROUP.to_raw(),
84 )),
85 p if p == PropertyIdentifier::GROUP_ID => Ok(PropertyValue::Unsigned(self.group_id)),
86 p if p == PropertyIdentifier::GROUP_MEMBERS => {
87 let items: Vec<PropertyValue> = self
88 .group_members
89 .iter()
90 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
91 .collect();
92 Ok(PropertyValue::List(items))
93 }
94 p if p == PropertyIdentifier::GROUP_MODE => {
95 Ok(PropertyValue::Enumerated(self.group_mode))
96 }
97 p if p == PropertyIdentifier::LANDING_CALLS => {
98 Ok(PropertyValue::Unsigned(self.landing_calls))
99 }
100 p if p == PropertyIdentifier::LANDING_CALL_CONTROL => {
101 Ok(PropertyValue::Enumerated(self.landing_call_control))
102 }
103 _ => Err(common::unknown_property_error()),
104 }
105 }
106
107 fn write_property(
108 &mut self,
109 property: PropertyIdentifier,
110 _array_index: Option<u32>,
111 value: PropertyValue,
112 _priority: Option<u8>,
113 ) -> Result<(), Error> {
114 if let Some(result) =
115 common::write_out_of_service(&mut self.out_of_service, property, &value)
116 {
117 return result;
118 }
119 if let Some(result) = common::write_description(&mut self.description, property, &value) {
120 return result;
121 }
122 match property {
123 p if p == PropertyIdentifier::GROUP_ID => {
124 if let PropertyValue::Unsigned(v) = value {
125 self.group_id = v;
126 Ok(())
127 } else {
128 Err(common::invalid_data_type_error())
129 }
130 }
131 p if p == PropertyIdentifier::GROUP_MODE => {
132 if let PropertyValue::Enumerated(v) = value {
133 self.group_mode = v;
134 Ok(())
135 } else {
136 Err(common::invalid_data_type_error())
137 }
138 }
139 p if p == PropertyIdentifier::LANDING_CALL_CONTROL => {
140 if let PropertyValue::Enumerated(v) = value {
141 self.landing_call_control = v;
142 Ok(())
143 } else {
144 Err(common::invalid_data_type_error())
145 }
146 }
147 _ => Err(common::write_access_denied_error()),
148 }
149 }
150
151 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
152 static PROPS: &[PropertyIdentifier] = &[
153 PropertyIdentifier::OBJECT_IDENTIFIER,
154 PropertyIdentifier::OBJECT_NAME,
155 PropertyIdentifier::DESCRIPTION,
156 PropertyIdentifier::OBJECT_TYPE,
157 PropertyIdentifier::GROUP_ID,
158 PropertyIdentifier::GROUP_MEMBERS,
159 PropertyIdentifier::GROUP_MODE,
160 PropertyIdentifier::LANDING_CALLS,
161 PropertyIdentifier::LANDING_CALL_CONTROL,
162 PropertyIdentifier::STATUS_FLAGS,
163 PropertyIdentifier::OUT_OF_SERVICE,
164 PropertyIdentifier::RELIABILITY,
165 ];
166 Cow::Borrowed(PROPS)
167 }
168}
169
170pub struct EscalatorObject {
176 oid: ObjectIdentifier,
177 name: String,
178 description: String,
179 escalator_mode: u32,
181 fault_signals: Vec<u64>,
183 energy_meter: f32,
185 energy_meter_ref: Vec<u8>,
187 power_mode: bool,
189 operation_direction: u32,
191 status_flags: StatusFlags,
192 out_of_service: bool,
193 reliability: u32,
194}
195
196impl EscalatorObject {
197 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
199 let oid = ObjectIdentifier::new(ObjectType::ESCALATOR, instance)?;
200 Ok(Self {
201 oid,
202 name: name.into(),
203 description: String::new(),
204 escalator_mode: 0, fault_signals: Vec::new(),
206 energy_meter: 0.0,
207 energy_meter_ref: Vec::new(),
208 power_mode: false,
209 operation_direction: 0, status_flags: StatusFlags::empty(),
211 out_of_service: false,
212 reliability: 0,
213 })
214 }
215}
216
217impl BACnetObject for EscalatorObject {
218 fn object_identifier(&self) -> ObjectIdentifier {
219 self.oid
220 }
221
222 fn object_name(&self) -> &str {
223 &self.name
224 }
225
226 fn read_property(
227 &self,
228 property: PropertyIdentifier,
229 array_index: Option<u32>,
230 ) -> Result<PropertyValue, Error> {
231 if let Some(result) = read_common_properties!(self, property, array_index) {
232 return result;
233 }
234 match property {
235 p if p == PropertyIdentifier::OBJECT_TYPE => {
236 Ok(PropertyValue::Enumerated(ObjectType::ESCALATOR.to_raw()))
237 }
238 p if p == PropertyIdentifier::ESCALATOR_MODE => {
239 Ok(PropertyValue::Enumerated(self.escalator_mode))
240 }
241 p if p == PropertyIdentifier::FAULT_SIGNALS => {
242 let items: Vec<PropertyValue> = self
243 .fault_signals
244 .iter()
245 .map(|v| PropertyValue::Unsigned(*v))
246 .collect();
247 Ok(PropertyValue::List(items))
248 }
249 p if p == PropertyIdentifier::ENERGY_METER => {
250 Ok(PropertyValue::Real(self.energy_meter))
251 }
252 p if p == PropertyIdentifier::ENERGY_METER_REF => {
253 Ok(PropertyValue::OctetString(self.energy_meter_ref.clone()))
254 }
255 p if p == PropertyIdentifier::POWER_MODE => Ok(PropertyValue::Boolean(self.power_mode)),
256 p if p == PropertyIdentifier::OPERATION_DIRECTION => {
257 Ok(PropertyValue::Enumerated(self.operation_direction))
258 }
259 _ => Err(common::unknown_property_error()),
260 }
261 }
262
263 fn write_property(
264 &mut self,
265 property: PropertyIdentifier,
266 _array_index: Option<u32>,
267 value: PropertyValue,
268 _priority: Option<u8>,
269 ) -> Result<(), Error> {
270 if let Some(result) =
271 common::write_out_of_service(&mut self.out_of_service, property, &value)
272 {
273 return result;
274 }
275 if let Some(result) = common::write_description(&mut self.description, property, &value) {
276 return result;
277 }
278 match property {
279 p if p == PropertyIdentifier::ESCALATOR_MODE => {
280 if let PropertyValue::Enumerated(v) = value {
281 if v > 4 {
282 return Err(common::value_out_of_range_error());
283 }
284 self.escalator_mode = v;
285 Ok(())
286 } else {
287 Err(common::invalid_data_type_error())
288 }
289 }
290 p if p == PropertyIdentifier::OPERATION_DIRECTION => {
291 if let PropertyValue::Enumerated(v) = value {
292 if v > 3 {
293 return Err(common::value_out_of_range_error());
294 }
295 self.operation_direction = v;
296 Ok(())
297 } else {
298 Err(common::invalid_data_type_error())
299 }
300 }
301 _ => Err(common::write_access_denied_error()),
302 }
303 }
304
305 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
306 static PROPS: &[PropertyIdentifier] = &[
307 PropertyIdentifier::OBJECT_IDENTIFIER,
308 PropertyIdentifier::OBJECT_NAME,
309 PropertyIdentifier::DESCRIPTION,
310 PropertyIdentifier::OBJECT_TYPE,
311 PropertyIdentifier::ESCALATOR_MODE,
312 PropertyIdentifier::FAULT_SIGNALS,
313 PropertyIdentifier::ENERGY_METER,
314 PropertyIdentifier::ENERGY_METER_REF,
315 PropertyIdentifier::POWER_MODE,
316 PropertyIdentifier::OPERATION_DIRECTION,
317 PropertyIdentifier::STATUS_FLAGS,
318 PropertyIdentifier::OUT_OF_SERVICE,
319 PropertyIdentifier::RELIABILITY,
320 ];
321 Cow::Borrowed(PROPS)
322 }
323}
324
325pub struct LiftObject {
331 oid: ObjectIdentifier,
332 name: String,
333 description: String,
334 tracking_value: u64,
336 car_position: u64,
338 car_moving_direction: u32,
340 car_door_status: Vec<u64>,
342 car_load: u64,
344 landing_doors: u64,
346 floor_text: Vec<String>,
348 energy_meter: f32,
350 status_flags: StatusFlags,
351 out_of_service: bool,
352 reliability: u32,
353}
354
355impl LiftObject {
356 pub fn new(instance: u32, name: impl Into<String>, num_floors: usize) -> Result<Self, Error> {
360 let oid = ObjectIdentifier::new(ObjectType::LIFT, instance)?;
361 let floor_text = (1..=num_floors).map(|i| format!("Floor {i}")).collect();
362 Ok(Self {
363 oid,
364 name: name.into(),
365 description: String::new(),
366 tracking_value: 1,
367 car_position: 1,
368 car_moving_direction: 1, car_door_status: Vec::new(),
370 car_load: 0,
371 landing_doors: num_floors as u64,
372 floor_text,
373 energy_meter: 0.0,
374 status_flags: StatusFlags::empty(),
375 out_of_service: false,
376 reliability: 0,
377 })
378 }
379}
380
381impl BACnetObject for LiftObject {
382 fn object_identifier(&self) -> ObjectIdentifier {
383 self.oid
384 }
385
386 fn object_name(&self) -> &str {
387 &self.name
388 }
389
390 fn read_property(
391 &self,
392 property: PropertyIdentifier,
393 array_index: Option<u32>,
394 ) -> Result<PropertyValue, Error> {
395 if let Some(result) = read_common_properties!(self, property, array_index) {
396 return result;
397 }
398 match property {
399 p if p == PropertyIdentifier::OBJECT_TYPE => {
400 Ok(PropertyValue::Enumerated(ObjectType::LIFT.to_raw()))
401 }
402 p if p == PropertyIdentifier::TRACKING_VALUE => {
403 Ok(PropertyValue::Unsigned(self.tracking_value))
404 }
405 p if p == PropertyIdentifier::CAR_POSITION => {
406 Ok(PropertyValue::Unsigned(self.car_position))
407 }
408 p if p == PropertyIdentifier::CAR_MOVING_DIRECTION => {
409 Ok(PropertyValue::Enumerated(self.car_moving_direction))
410 }
411 p if p == PropertyIdentifier::CAR_DOOR_STATUS => {
412 let items: Vec<PropertyValue> = self
413 .car_door_status
414 .iter()
415 .map(|v| PropertyValue::Unsigned(*v))
416 .collect();
417 Ok(PropertyValue::List(items))
418 }
419 p if p == PropertyIdentifier::CAR_LOAD => Ok(PropertyValue::Unsigned(self.car_load)),
420 p if p == PropertyIdentifier::LANDING_DOOR_STATUS => {
421 Ok(PropertyValue::Unsigned(self.landing_doors))
422 }
423 p if p == PropertyIdentifier::FLOOR_TEXT => {
424 let items: Vec<PropertyValue> = self
425 .floor_text
426 .iter()
427 .map(|s| PropertyValue::CharacterString(s.clone()))
428 .collect();
429 Ok(PropertyValue::List(items))
430 }
431 p if p == PropertyIdentifier::ENERGY_METER => {
432 Ok(PropertyValue::Real(self.energy_meter))
433 }
434 _ => Err(common::unknown_property_error()),
435 }
436 }
437
438 fn write_property(
439 &mut self,
440 property: PropertyIdentifier,
441 _array_index: Option<u32>,
442 value: PropertyValue,
443 _priority: Option<u8>,
444 ) -> Result<(), Error> {
445 if let Some(result) =
446 common::write_out_of_service(&mut self.out_of_service, property, &value)
447 {
448 return result;
449 }
450 if let Some(result) = common::write_description(&mut self.description, property, &value) {
451 return result;
452 }
453 match property {
454 p if p == PropertyIdentifier::TRACKING_VALUE => {
455 if let PropertyValue::Unsigned(v) = value {
456 self.tracking_value = v;
457 Ok(())
458 } else {
459 Err(common::invalid_data_type_error())
460 }
461 }
462 p if p == PropertyIdentifier::CAR_POSITION => {
463 if let PropertyValue::Unsigned(v) = value {
464 self.car_position = v;
465 Ok(())
466 } else {
467 Err(common::invalid_data_type_error())
468 }
469 }
470 p if p == PropertyIdentifier::CAR_MOVING_DIRECTION => {
471 if let PropertyValue::Enumerated(v) = value {
472 if v > 3 {
473 return Err(common::value_out_of_range_error());
474 }
475 self.car_moving_direction = v;
476 Ok(())
477 } else {
478 Err(common::invalid_data_type_error())
479 }
480 }
481 p if p == PropertyIdentifier::CAR_LOAD => {
482 if let PropertyValue::Unsigned(v) = value {
483 if v > 100 {
484 return Err(common::value_out_of_range_error());
485 }
486 self.car_load = v;
487 Ok(())
488 } else {
489 Err(common::invalid_data_type_error())
490 }
491 }
492 _ => Err(common::write_access_denied_error()),
493 }
494 }
495
496 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
497 static PROPS: &[PropertyIdentifier] = &[
498 PropertyIdentifier::OBJECT_IDENTIFIER,
499 PropertyIdentifier::OBJECT_NAME,
500 PropertyIdentifier::DESCRIPTION,
501 PropertyIdentifier::OBJECT_TYPE,
502 PropertyIdentifier::TRACKING_VALUE,
503 PropertyIdentifier::CAR_POSITION,
504 PropertyIdentifier::CAR_MOVING_DIRECTION,
505 PropertyIdentifier::CAR_DOOR_STATUS,
506 PropertyIdentifier::CAR_LOAD,
507 PropertyIdentifier::LANDING_DOOR_STATUS,
508 PropertyIdentifier::FLOOR_TEXT,
509 PropertyIdentifier::ENERGY_METER,
510 PropertyIdentifier::STATUS_FLAGS,
511 PropertyIdentifier::OUT_OF_SERVICE,
512 PropertyIdentifier::RELIABILITY,
513 ];
514 Cow::Borrowed(PROPS)
515 }
516}
517
518#[cfg(test)]
523mod tests {
524 use super::*;
525
526 #[test]
529 fn elevator_group_create_and_read_defaults() {
530 let eg = ElevatorGroupObject::new(1, "EG-1").unwrap();
531 assert_eq!(eg.object_name(), "EG-1");
532 assert_eq!(
533 eg.read_property(PropertyIdentifier::GROUP_ID, None)
534 .unwrap(),
535 PropertyValue::Unsigned(0)
536 );
537 assert_eq!(
538 eg.read_property(PropertyIdentifier::GROUP_MEMBERS, None)
539 .unwrap(),
540 PropertyValue::List(vec![])
541 );
542 assert_eq!(
543 eg.read_property(PropertyIdentifier::GROUP_MODE, None)
544 .unwrap(),
545 PropertyValue::Enumerated(0) );
547 }
548
549 #[test]
550 fn elevator_group_object_type() {
551 let eg = ElevatorGroupObject::new(1, "EG-1").unwrap();
552 assert_eq!(
553 eg.read_property(PropertyIdentifier::OBJECT_TYPE, None)
554 .unwrap(),
555 PropertyValue::Enumerated(ObjectType::ELEVATOR_GROUP.to_raw())
556 );
557 }
558
559 #[test]
560 fn elevator_group_add_members() {
561 let mut eg = ElevatorGroupObject::new(1, "EG-1").unwrap();
562 let lift1 = ObjectIdentifier::new(ObjectType::LIFT, 1).unwrap();
563 let lift2 = ObjectIdentifier::new(ObjectType::LIFT, 2).unwrap();
564 eg.add_member(lift1);
565 eg.add_member(lift2);
566 assert_eq!(
567 eg.read_property(PropertyIdentifier::GROUP_MEMBERS, None)
568 .unwrap(),
569 PropertyValue::List(vec![
570 PropertyValue::ObjectIdentifier(lift1),
571 PropertyValue::ObjectIdentifier(lift2),
572 ])
573 );
574 }
575
576 #[test]
577 fn elevator_group_read_landing_calls() {
578 let eg = ElevatorGroupObject::new(1, "EG-1").unwrap();
579 assert_eq!(
580 eg.read_property(PropertyIdentifier::LANDING_CALLS, None)
581 .unwrap(),
582 PropertyValue::Unsigned(0)
583 );
584 }
585
586 #[test]
587 fn elevator_group_property_list() {
588 let eg = ElevatorGroupObject::new(1, "EG-1").unwrap();
589 let list = eg.property_list();
590 assert!(list.contains(&PropertyIdentifier::GROUP_ID));
591 assert!(list.contains(&PropertyIdentifier::GROUP_MEMBERS));
592 assert!(list.contains(&PropertyIdentifier::GROUP_MODE));
593 assert!(list.contains(&PropertyIdentifier::LANDING_CALLS));
594 assert!(list.contains(&PropertyIdentifier::LANDING_CALL_CONTROL));
595 assert!(list.contains(&PropertyIdentifier::STATUS_FLAGS));
596 }
597
598 #[test]
601 fn escalator_create_and_read_defaults() {
602 let esc = EscalatorObject::new(1, "ESC-1").unwrap();
603 assert_eq!(esc.object_name(), "ESC-1");
604 assert_eq!(
605 esc.read_property(PropertyIdentifier::ESCALATOR_MODE, None)
606 .unwrap(),
607 PropertyValue::Enumerated(0) );
609 assert_eq!(
610 esc.read_property(PropertyIdentifier::ENERGY_METER, None)
611 .unwrap(),
612 PropertyValue::Real(0.0)
613 );
614 assert_eq!(
615 esc.read_property(PropertyIdentifier::POWER_MODE, None)
616 .unwrap(),
617 PropertyValue::Boolean(false)
618 );
619 }
620
621 #[test]
622 fn escalator_object_type() {
623 let esc = EscalatorObject::new(1, "ESC-1").unwrap();
624 assert_eq!(
625 esc.read_property(PropertyIdentifier::OBJECT_TYPE, None)
626 .unwrap(),
627 PropertyValue::Enumerated(ObjectType::ESCALATOR.to_raw())
628 );
629 }
630
631 #[test]
632 fn escalator_read_operation_direction() {
633 let esc = EscalatorObject::new(1, "ESC-1").unwrap();
634 assert_eq!(
635 esc.read_property(PropertyIdentifier::OPERATION_DIRECTION, None)
636 .unwrap(),
637 PropertyValue::Enumerated(0) );
639 }
640
641 #[test]
642 fn escalator_read_fault_signals() {
643 let esc = EscalatorObject::new(1, "ESC-1").unwrap();
644 assert_eq!(
645 esc.read_property(PropertyIdentifier::FAULT_SIGNALS, None)
646 .unwrap(),
647 PropertyValue::List(vec![])
648 );
649 }
650
651 #[test]
652 fn escalator_property_list() {
653 let esc = EscalatorObject::new(1, "ESC-1").unwrap();
654 let list = esc.property_list();
655 assert!(list.contains(&PropertyIdentifier::ESCALATOR_MODE));
656 assert!(list.contains(&PropertyIdentifier::FAULT_SIGNALS));
657 assert!(list.contains(&PropertyIdentifier::ENERGY_METER));
658 assert!(list.contains(&PropertyIdentifier::ENERGY_METER_REF));
659 assert!(list.contains(&PropertyIdentifier::POWER_MODE));
660 assert!(list.contains(&PropertyIdentifier::OPERATION_DIRECTION));
661 assert!(list.contains(&PropertyIdentifier::STATUS_FLAGS));
662 }
663
664 #[test]
667 fn lift_create_and_read_defaults() {
668 let lift = LiftObject::new(1, "LIFT-1", 10).unwrap();
669 assert_eq!(lift.object_name(), "LIFT-1");
670 assert_eq!(
671 lift.read_property(PropertyIdentifier::TRACKING_VALUE, None)
672 .unwrap(),
673 PropertyValue::Unsigned(1)
674 );
675 assert_eq!(
676 lift.read_property(PropertyIdentifier::CAR_POSITION, None)
677 .unwrap(),
678 PropertyValue::Unsigned(1)
679 );
680 assert_eq!(
681 lift.read_property(PropertyIdentifier::CAR_MOVING_DIRECTION, None)
682 .unwrap(),
683 PropertyValue::Enumerated(1) );
685 }
686
687 #[test]
688 fn lift_object_type() {
689 let lift = LiftObject::new(1, "LIFT-1", 5).unwrap();
690 assert_eq!(
691 lift.read_property(PropertyIdentifier::OBJECT_TYPE, None)
692 .unwrap(),
693 PropertyValue::Enumerated(ObjectType::LIFT.to_raw())
694 );
695 }
696
697 #[test]
698 fn lift_floor_text() {
699 let lift = LiftObject::new(1, "LIFT-1", 3).unwrap();
700 assert_eq!(
701 lift.read_property(PropertyIdentifier::FLOOR_TEXT, None)
702 .unwrap(),
703 PropertyValue::List(vec![
704 PropertyValue::CharacterString("Floor 1".into()),
705 PropertyValue::CharacterString("Floor 2".into()),
706 PropertyValue::CharacterString("Floor 3".into()),
707 ])
708 );
709 }
710
711 #[test]
712 fn lift_read_car_load() {
713 let lift = LiftObject::new(1, "LIFT-1", 5).unwrap();
714 assert_eq!(
715 lift.read_property(PropertyIdentifier::CAR_LOAD, None)
716 .unwrap(),
717 PropertyValue::Unsigned(0)
718 );
719 }
720
721 #[test]
722 fn lift_write_tracking_value() {
723 let mut lift = LiftObject::new(1, "LIFT-1", 10).unwrap();
724 lift.write_property(
725 PropertyIdentifier::TRACKING_VALUE,
726 None,
727 PropertyValue::Unsigned(5),
728 None,
729 )
730 .unwrap();
731 assert_eq!(
732 lift.read_property(PropertyIdentifier::TRACKING_VALUE, None)
733 .unwrap(),
734 PropertyValue::Unsigned(5)
735 );
736 }
737
738 #[test]
739 fn lift_write_car_load_out_of_range() {
740 let mut lift = LiftObject::new(1, "LIFT-1", 5).unwrap();
741 let result = lift.write_property(
742 PropertyIdentifier::CAR_LOAD,
743 None,
744 PropertyValue::Unsigned(101),
745 None,
746 );
747 assert!(result.is_err());
748 }
749
750 #[test]
751 fn lift_read_landing_doors() {
752 let lift = LiftObject::new(1, "LIFT-1", 8).unwrap();
753 assert_eq!(
754 lift.read_property(PropertyIdentifier::LANDING_DOOR_STATUS, None)
755 .unwrap(),
756 PropertyValue::Unsigned(8)
757 );
758 }
759
760 #[test]
761 fn lift_read_energy_meter() {
762 let lift = LiftObject::new(1, "LIFT-1", 5).unwrap();
763 assert_eq!(
764 lift.read_property(PropertyIdentifier::ENERGY_METER, None)
765 .unwrap(),
766 PropertyValue::Real(0.0)
767 );
768 }
769
770 #[test]
771 fn lift_property_list() {
772 let lift = LiftObject::new(1, "LIFT-1", 5).unwrap();
773 let list = lift.property_list();
774 assert!(list.contains(&PropertyIdentifier::TRACKING_VALUE));
775 assert!(list.contains(&PropertyIdentifier::CAR_POSITION));
776 assert!(list.contains(&PropertyIdentifier::CAR_MOVING_DIRECTION));
777 assert!(list.contains(&PropertyIdentifier::CAR_DOOR_STATUS));
778 assert!(list.contains(&PropertyIdentifier::CAR_LOAD));
779 assert!(list.contains(&PropertyIdentifier::LANDING_DOOR_STATUS));
780 assert!(list.contains(&PropertyIdentifier::FLOOR_TEXT));
781 assert!(list.contains(&PropertyIdentifier::ENERGY_METER));
782 assert!(list.contains(&PropertyIdentifier::STATUS_FLAGS));
783 }
784}