A clone of: https://github.com/nutechsoftware/alarmdecoder This is requires as they dropped support for older firmware releases w/o building in backward compatibility code, and they had previously hardcoded pyserial to a python2 only version.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

316 lines
13 KiB

  1. import time
  2. from unittest import TestCase
  3. from mock import Mock, MagicMock, patch
  4. from alarmdecoder.decoder import AlarmDecoder
  5. from alarmdecoder.devices import USBDevice
  6. from alarmdecoder.messages import Message, RFMessage, LRRMessage, ExpanderMessage
  7. from alarmdecoder.event.event import Event, EventHandler
  8. from alarmdecoder.zonetracking import Zonetracker
  9. class TestAlarmDecoder(TestCase):
  10. def setUp(self):
  11. self._panicked = False
  12. self._relay_changed = False
  13. self._power_changed = False
  14. self._alarmed = False
  15. self._bypassed = False
  16. self._battery = False
  17. self._fire = False
  18. self._armed = False
  19. self._got_config = False
  20. self._message_received = False
  21. self._rfx_message_received = False
  22. self._lrr_message_received = False
  23. self._expander_message_received = False
  24. self._sending_received_status = None
  25. self._alarm_restored = False
  26. self._on_boot_received = False
  27. self._zone_faulted = None
  28. self._zone_restored = None
  29. self._device = Mock(spec=USBDevice)
  30. self._device.on_open = EventHandler(Event(), self._device)
  31. self._device.on_close = EventHandler(Event(), self._device)
  32. self._device.on_read = EventHandler(Event(), self._device)
  33. self._device.on_write = EventHandler(Event(), self._device)
  34. self._decoder = AlarmDecoder(self._device)
  35. self._decoder.on_panic += self.on_panic
  36. self._decoder.on_relay_changed += self.on_relay_changed
  37. self._decoder.on_power_changed += self.on_power_changed
  38. self._decoder.on_alarm += self.on_alarm
  39. self._decoder.on_alarm_restored += self.on_alarm_restored
  40. self._decoder.on_bypass += self.on_bypass
  41. self._decoder.on_low_battery += self.on_battery
  42. self._decoder.on_fire += self.on_fire
  43. self._decoder.on_arm += self.on_arm
  44. self._decoder.on_disarm += self.on_disarm
  45. self._decoder.on_config_received += self.on_config
  46. self._decoder.on_message += self.on_message
  47. self._decoder.on_rfx_message += self.on_rfx_message
  48. self._decoder.on_lrr_message += self.on_lrr_message
  49. self._decoder.on_expander_message += self.on_expander_message
  50. self._decoder.on_sending_received += self.on_sending_received
  51. self._decoder.on_boot += self.on_boot
  52. self._decoder.on_zone_fault += self.on_zone_fault
  53. self._decoder.on_zone_restore += self.on_zone_restore
  54. self._decoder.address_mask = int('ffffffff', 16)
  55. self._decoder.open()
  56. def tearDown(self):
  57. pass
  58. def on_panic(self, sender, *args, **kwargs):
  59. self._panicked = kwargs['status']
  60. def on_relay_changed(self, sender, *args, **kwargs):
  61. self._relay_changed = True
  62. def on_power_changed(self, sender, *args, **kwargs):
  63. self._power_changed = kwargs['status']
  64. def on_alarm(self, sender, *args, **kwargs):
  65. self._alarmed = True
  66. def on_alarm_restored(self, sender, *args, **kwargs):
  67. self._alarm_restored = True
  68. def on_bypass(self, sender, *args, **kwargs):
  69. self._bypassed = kwargs['status']
  70. def on_battery(self, sender, *args, **kwargs):
  71. self._battery = kwargs['status']
  72. def on_fire(self, sender, *args, **kwargs):
  73. self._fire = kwargs['status']
  74. def on_arm(self, sender, *args, **kwargs):
  75. self._armed = True
  76. def on_disarm(self, sender, *args, **kwargs):
  77. self._armed = False
  78. def on_config(self, sender, *args, **kwargs):
  79. self._got_config = True
  80. def on_message(self, sender, *args, **kwargs):
  81. self._message_received = True
  82. def on_rfx_message(self, sender, *args, **kwargs):
  83. self._rfx_message_received = True
  84. def on_lrr_message(self, sender, *args, **kwargs):
  85. self._lrr_message_received = True
  86. def on_expander_message(self, sender, *args, **kwargs):
  87. self._expander_message_received = True
  88. def on_sending_received(self, sender, *args, **kwargs):
  89. self._sending_received_status = kwargs['status']
  90. def on_boot(self, sender, *args, **kwargs):
  91. self._on_boot_received = True
  92. def on_zone_fault(self, sender, *args, **kwargs):
  93. self._zone_faulted = kwargs['zone']
  94. def on_zone_restore(self, sender, *args, **kwargs):
  95. self._zone_restored = kwargs['zone']
  96. def test_open(self):
  97. self._decoder.open()
  98. self._device.open.assert_any_calls()
  99. def test_close(self):
  100. self._decoder.open()
  101. self._decoder.close()
  102. self._device.close.assert_any_calls()
  103. def test_send(self):
  104. self._decoder.send('test')
  105. self._device.write.assert_called_with('test')
  106. def test_get_config(self):
  107. self._decoder.get_config()
  108. self._device.write.assert_called_with("C\r")
  109. def test_save_config(self):
  110. self._decoder.save_config()
  111. self._device.write.assert_any_calls()
  112. def test_reboot(self):
  113. self._decoder.reboot()
  114. self._device.write.assert_called_with('=')
  115. def test_fault(self):
  116. self._decoder.fault_zone(1)
  117. self._device.write.assert_called_with("L{0:02}{1}\r".format(1, 1))
  118. def test_fault_wireproblem(self):
  119. self._decoder.fault_zone(1, simulate_wire_problem=True)
  120. self._device.write.assert_called_with("L{0:02}{1}\r".format(1, 2))
  121. def test_clear_zone(self):
  122. self._decoder.clear_zone(1)
  123. self._device.write.assert_called_with("L{0:02}0\r".format(1))
  124. def test_message(self):
  125. msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  126. self.assertIsInstance(msg, Message)
  127. self._decoder._on_read(self, data='[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  128. self.assertTrue(self._message_received)
  129. def test_message_kpm(self):
  130. msg = self._decoder._handle_message('!KPM:[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  131. self.assertIsInstance(msg, Message)
  132. self._decoder._on_read(self, data='[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  133. self.assertTrue(self._message_received)
  134. def test_expander_message(self):
  135. msg = self._decoder._handle_message('!EXP:07,01,01')
  136. self.assertIsInstance(msg, ExpanderMessage)
  137. self._decoder._on_read(self, data='!EXP:07,01,01')
  138. self.assertTrue(self._expander_message_received)
  139. def test_relay_message(self):
  140. self._decoder.open()
  141. msg = self._decoder._handle_message('!REL:12,01,01')
  142. self.assertIsInstance(msg, ExpanderMessage)
  143. self.assertEqual(self._relay_changed, True)
  144. def test_rfx_message(self):
  145. msg = self._decoder._handle_message('!RFX:0180036,80')
  146. self.assertIsInstance(msg, RFMessage)
  147. self.assertTrue(self._rfx_message_received)
  148. def test_panic(self):
  149. self._decoder.open()
  150. msg = self._decoder._handle_message('!LRR:012,1,ALARM_PANIC')
  151. self.assertEqual(self._panicked, True)
  152. msg = self._decoder._handle_message('!LRR:012,1,CANCEL')
  153. self.assertEqual(self._panicked, False)
  154. self.assertIsInstance(msg, LRRMessage)
  155. def test_config_message(self):
  156. self._decoder.open()
  157. msg = self._decoder._handle_message('!CONFIG>ADDRESS=18&CONFIGBITS=ff00&LRR=N&EXP=NNNNN&REL=NNNN&MASK=ffffffff&DEDUPLICATE=N')
  158. self.assertEqual(self._decoder.address, 18)
  159. self.assertEqual(self._decoder.configbits, int('ff00', 16))
  160. self.assertEqual(self._decoder.address_mask, int('ffffffff', 16))
  161. self.assertEqual(self._decoder.emulate_zone, [False for x in range(5)])
  162. self.assertEqual(self._decoder.emulate_relay, [False for x in range(4)])
  163. self.assertEqual(self._decoder.emulate_lrr, False)
  164. self.assertEqual(self._decoder.deduplicate, False)
  165. self.assertEqual(self._got_config, True)
  166. def test_power_changed_event(self):
  167. msg = self._decoder._handle_message('[0000000100000000----],000,[f707000600e5800c0c020000]," "')
  168. self.assertEqual(self._power_changed, False) # Not set first time we hit it.
  169. msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  170. self.assertEqual(self._power_changed, False)
  171. msg = self._decoder._handle_message('[0000000100000000----],000,[f707000600e5800c0c020000]," "')
  172. self.assertEqual(self._power_changed, True)
  173. def test_alarm_event(self):
  174. msg = self._decoder._handle_message('[0000000000100000----],000,[f707000600e5800c0c020000]," "')
  175. self.assertEqual(self._alarmed, False) # Not set first time we hit it.
  176. msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  177. self.assertEqual(self._alarmed, False)
  178. self.assertEqual(self._alarm_restored, True)
  179. msg = self._decoder._handle_message('[0000000000100000----],000,[f707000600e5800c0c020000]," "')
  180. self.assertEqual(self._alarmed, True)
  181. def test_zone_bypassed_event(self):
  182. msg = self._decoder._handle_message('[0000001000000000----],000,[f707000600e5800c0c020000]," "')
  183. self.assertEqual(self._bypassed, False) # Not set first time we hit it.
  184. msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  185. self.assertEqual(self._bypassed, False)
  186. msg = self._decoder._handle_message('[0000001000000000----],000,[f707000600e5800c0c020000]," "')
  187. self.assertEqual(self._bypassed, True)
  188. def test_armed_away_event(self):
  189. msg = self._decoder._handle_message('[0100000000000000----],000,[f707000600e5800c0c020000]," "')
  190. self.assertEqual(self._armed, False) # Not set first time we hit it.
  191. msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  192. self.assertEqual(self._armed, False)
  193. msg = self._decoder._handle_message('[0100000000000000----],000,[f707000600e5800c0c020000]," "')
  194. self.assertEqual(self._armed, True)
  195. self._armed = False
  196. msg = self._decoder._handle_message('[0010000000000000----],000,[f707000600e5800c0c020000]," "')
  197. self.assertEqual(self._armed, False) # Not set first time we hit it.
  198. msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  199. self.assertEqual(self._armed, False)
  200. msg = self._decoder._handle_message('[0010000000000000----],000,[f707000600e5800c0c020000]," "')
  201. self.assertEqual(self._armed, True)
  202. def test_battery_low_event(self):
  203. msg = self._decoder._handle_message('[0000000000010000----],000,[f707000600e5800c0c020000]," "')
  204. self.assertEqual(self._battery, True)
  205. # force the timeout to expire.
  206. with patch.object(time, 'time', return_value=self._decoder._battery_status[1] + 35):
  207. msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  208. self.assertEqual(self._battery, False)
  209. def test_fire_alarm_event(self):
  210. msg = self._decoder._handle_message('[0000000000000100----],000,[f707000600e5800c0c020000]," "')
  211. self.assertEqual(self._fire, True)
  212. # force the timeout to expire.
  213. with patch.object(time, 'time', return_value=self._decoder._battery_status[1] + 35):
  214. msg = self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000]," "')
  215. self.assertEqual(self._fire, False)
  216. def test_hit_for_faults(self):
  217. self._decoder._handle_message('[0000000000000000----],000,[f707000600e5800c0c020000],"Hit * for faults "')
  218. self._decoder._device.write.assert_called_with('*')
  219. def test_sending_received(self):
  220. self._decoder._on_read(self, data='!Sending.done')
  221. self.assertTrue(self._sending_received_status)
  222. self._decoder._on_read(self, data='!Sending.....done')
  223. self.assertFalse(self._sending_received_status)
  224. def test_boot(self):
  225. self._decoder._on_read(self, data='!Ready')
  226. self.assertTrue(self._on_boot_received)
  227. def test_zone_fault_and_restore(self):
  228. self._decoder._on_read(self, data='[00010001000000000A--],003,[f70000051003000008020000000000],"FAULT 03 "')
  229. self.assertEqual(self._zone_faulted, 3)
  230. self._decoder._on_read(self, data='[00010001000000000A--],004,[f70000051003000008020000000000],"FAULT 04 "')
  231. self.assertEqual(self._zone_faulted, 4)
  232. self._decoder._on_read(self, data='[00010001000000000A--],005,[f70000051003000008020000000000],"FAULT 05 "')
  233. self.assertEqual(self._zone_faulted, 5)
  234. self._decoder._on_read(self, data='[00010001000000000A--],004,[f70000051003000008020000000000],"FAULT 04 "')
  235. self.assertEqual(self._zone_restored, 3)