55May be used as a command line tool for testing TSIC input.
66"""
77
8- __all__ = [ 'ZacWireInputChannel' , 'Measurement' , 'TsicInputChannel' ]
8+ __all__ = [ 'ZacWireInputChannel' , 'Measurement' , 'TsicInputChannel' , 'Error' , 'PigpioNotConnectedError' ]
99
1010__author__ = 'Holger Fleischmann'
1111__copyright__ = 'Copyright 2018, Holger Fleischmann, Bavaria/Germany'
1212__license__ = 'Apache License 2.0'
1313
1414from datetime import datetime
1515import argparse
16+ import logging
1617
1718import pigpio
1819import threading
1920import time
2021
22+ logger = logging .getLogger ().getChild (__name__ )
23+
24+
25+ class Error (Exception ):
26+ """
27+ Base class of exceptions from this module.
28+ """
29+
30+ def __init__ (self , * args , ** kwargs ):
31+ Exception .__init__ (self , * args , ** kwargs )
32+
33+
34+ class PigpioNotConnectedError (Error ):
35+ """
36+ Raised when pigpio.pi is not connected.
37+ """
38+
39+ def __init__ (self , * args , ** kwargs ):
40+ Exception .__init__ (self , * args , ** kwargs )
41+
2142
2243class ZacWireInputChannel (object ):
2344 """
@@ -37,31 +58,41 @@ def __init__(self, pigpio_pi, gpio):
3758 Initialize ZACWire receiving channel on a GPIO.
3859 pigpio_pi is the pigpio.pi object to use for GPIO access.
3960 gpio is the GPIO as Broadcom chip number.
61+ Initializes the GPIO as input without pull-up or pull-down.
62+
63+ Raises PigpioNotConnectedError if pigpio_pi is not connected.
4064 """
4165 self .pi = pigpio_pi
4266 self .gpio = gpio
4367 self .__pi_callback = None
44-
45- self .pi .set_mode (self .gpio , pigpio .INPUT )
68+ if self .pi .connected :
69+ self .pi .set_mode (self .gpio , pigpio .INPUT )
70+ self .pi .set_pull_up_down (self .gpio , pigpio .PUD_OFF )
71+ else :
72+ raise PigpioNotConnectedError ('pigpio.pi is not connected, input for gpio ' + str (gpio ) + ' will not work' )
4673
4774 def start (self , callback ):
4875 """
4976 Start listening for data and pass received packet bytes
5077 to the a callback callback(status, [bytes]).
5178 Note that the callback is called by a pigpio thread.
79+
80+ Exceptions from the callback function are logged with standard
81+ python logging.
5282 """
5383 self .stop ()
5484 self .packet_callback = callback
55- self .__pi_callback = self .pi .callback (
56- self .gpio ,
57- pigpio .EITHER_EDGE ,
58- lambda gpio , level , tick : self .__gpio_callback (gpio , level , tick ))
85+ if self .pi .connected :
86+ self .__pi_callback = self .pi .callback (
87+ self .gpio ,
88+ pigpio .EITHER_EDGE ,
89+ lambda gpio , level , tick : self .__gpio_callback (gpio , level , tick ))
5990
6091 def stop (self ):
6192 """
6293 Stop listening for data.
6394 """
64- if not self .__pi_callback is None :
95+ if self .__pi_callback is not None :
6596 self .pi .set_watchdog (self .gpio , 0 )
6697 self .__pi_callback .cancel ()
6798 self .__pi_callback = None
@@ -73,7 +104,7 @@ def is_started(self):
73104 """
74105 Whether listening for data is running.
75106 """
76- return not self .__pi_callback is None
107+ return self .__pi_callback is not None
77108
78109 def __enter__ (self ):
79110 self .start (None )
@@ -82,7 +113,10 @@ def __exit__(self, exc_type, exc_val, exc_tb):
82113 self .stop ()
83114
84115 def __call_packet_callback (self , status , packet_bytes ):
85- self .packet_callback (status , packet_bytes )
116+ try :
117+ self .packet_callback (status , packet_bytes )
118+ except :
119+ logger .exception ('Exception from callback' + str (self .packet_callback ) + ' in ' + str (self ))
86120
87121 def __reset_packet (self ):
88122 self .__bit_ticks = None
@@ -91,15 +125,15 @@ def __reset_packet(self):
91125 self .__received_bytes = None
92126
93127 def __pass_any_packet_to_callback (self , status ):
94- if not self .__received_bytes is None :
128+ if self .__received_bytes is not None :
95129 # print('====> RECEIVED {0} STATUS {1}'.format(self.__received_bytes, status))
96130 self .__call_packet_callback (status , self .__received_bytes )
97131 self .__received_bytes = None
98132
99133 def __gpio_callback (self , gpio , level , tick ):
100134 if level == pigpio .LOW :
101135
102- if not self .__last_high_tick is None :
136+ if self .__last_high_tick is not None :
103137 high_ticks = pigpio .tickDiff (self .__last_high_tick , tick )
104138
105139 if high_ticks > 1000 :
@@ -111,7 +145,7 @@ def __gpio_callback(self, gpio, level, tick):
111145 self .__bit_count = 0
112146 self .__bit_ticks = None
113147
114- elif not self .__received_bytes is None and high_ticks > 150 :
148+ elif self .__received_bytes is not None and high_ticks > 150 :
115149 # next byte in packet
116150 # print('====> NEXT BYTE START')
117151 if self .__bit_count == 9 :
@@ -127,11 +161,11 @@ def __gpio_callback(self, gpio, level, tick):
127161
128162 elif level == pigpio .HIGH :
129163
130- if not self .__last_low_tick is None :
164+ if self .__last_low_tick is not None :
131165 low_ticks = pigpio .tickDiff (self .__last_low_tick , tick )
132166 # print('{0} @ {1} -> {2}: {3}'.format(gpio, tick, level, low_ticks))
133167
134- if not self .__received_bytes is None :
168+ if self .__received_bytes is not None :
135169 if self .__bit_ticks is None :
136170 # calibration T-strobe at begin of byte
137171 self .__bit_ticks = low_ticks
@@ -163,6 +197,9 @@ def __check_parity(self):
163197 self .__pass_any_packet_to_callback (self .STATUS_PARITY_ERROR )
164198 self .__reset_packet ()
165199
200+ def __repr__ (self , * args , ** kwargs ):
201+ return self .__class__ .__name__ + ' for GPIO ' + str (self .gpio )
202+
166203
167204class Measurement (object ):
168205 """
@@ -174,6 +211,9 @@ def __init__(self, degree_celsius, seconds_since_epoch):
174211 self .degree_celsius = degree_celsius
175212 self .seconds_since_epoch = seconds_since_epoch
176213
214+ def __eq__ (self , other ):
215+ return self .__dict__ == other .__dict__
216+
177217 def __repr__ (self , * args , ** kwargs ):
178218 if self .degree_celsius is None :
179219 return 'Undefined'
@@ -225,7 +265,7 @@ def stop(self):
225265 """
226266 Stop reading temperatures.
227267 """
228- if not self .__zacwire_channel is None :
268+ if self .__zacwire_channel is not None :
229269 self .__zacwire_channel .stop ()
230270
231271 def is_started (self ):
@@ -281,12 +321,15 @@ def __packet_received(self, status, packet_bytes):
281321 measurement = self .measurement
282322
283323 # print('====> Temperature {0}°C'.format(self.__degree_celsius))
284- if not self .__callback is None :
324+ if self .__callback is not None :
285325 self .__callback (measurement )
286326
287327 with self .__measure_waiting :
288328 self .__measure_waiting .notifyAll ()
289329
330+ def __repr__ (self , * args , ** kwargs ):
331+ return self .__class__ .__name__ + ' for GPIO ' + str (self .__zacwire_channel .gpio )
332+
290333
291334if __name__ == '__main__' :
292335 parser = argparse .ArgumentParser (description =
@@ -309,4 +352,3 @@ def __packet_received(self, status, packet_bytes):
309352 pass
310353 finally :
311354 pi .stop ()
312-
0 commit comments