class TheTapper(): """ Illuminate the neopixels in a counter-clockwise fashion with randomly generated colors. When you tap the playground express, the neopixels will stop changing and the program pauses. Tap again and the neopixels will start again. """ def __init__(self): # create an instance of the API self.p = PyMataCpx() print('Tap the playground express to stop the neopixels from moving.') print('Tap again, to start them up') print('The tap state will be printed to the console') # Start monitoring for tap events and # send event notifications to the tapped method. self.p.cpx_tap_start(self.tapped) self.go = True while True: try: # run the light show for neopixel in range(0, 10): if self.go: self.p.cpx_pixels_clear() self.p.cpx_pixels_show() r = random.randint(0, 254) g = random.randint(0, 254) b = random.randint(0, 254) self.p.cpx_pixel_set(neopixel, r, g, b) self.p.cpx_pixels_show() time.sleep(.2) else: self.p.cpx_pixels_clear() self.p.cpx_pixels_show() time.sleep(.001) except KeyboardInterrupt: # If you press control-C, cleanly exit self.p.cpx_pixels_clear() self.p.cpx_pixels_show() self.p.cpx_close_and_exit() def tapped(self, data): """ :param data: data[0] = data type (analog = 2, digital =32) data[1] = pin for device 27 data[2] = tap data - list of booleans. First value for 1 tap Second value for 2 taps """ # for any taps, toggle the go flag # print out the current tap state if data[2] != [False, False]: self.go = not self.go print(self.go)
class TheClapper: """ Turn LEDs in a counter-clockwise fashion with randomly generated colors. When you clap your hand loudly, the pixels will stop changing and the program exits. Clap again and they start moving again. """ def __init__(self): self.p = PyMataCpx() print('Clap your hands loudly to stop the neopixels from moving.') print('Clap again, to start them up') self.p.cpx_microphone_start(self.listen) self.go = True while True: try: # run the light show for neopixel in range(0, 10): if self.go: self.p.cpx_pixels_clear() self.p.cpx_pixels_show() r = random.randint(0, 254) g = random.randint(0, 254) b = random.randint(0, 254) self.p.cpx_pixel_set(neopixel, r, g, b) self.p.cpx_pixels_show() time.sleep(.2) else: self.p.cpx_pixels_clear() self.p.cpx_pixels_show() time.sleep(.001) except KeyboardInterrupt: # If you press control-C, cleanly exit self.p.cpx_pixels_clear() self.p.cpx_pixels_show() self.p.cpx_close_and_exit() def listen(self, data): """ Turn off the light show and exit :param data: data[0] = 2 indicating this is analog data data[1] = pin attached to mic- pin 4 data[3] = readings from microphone """ if data[2] > 600: # self.p.cpx_pixels_clear() # self.p.cpx_pixels_show() self.go = not self.go
class LightMeter: """ Using the light sensor, select and illuminate pixels based on the current light sensor reading. As the light sensor values increase, the pixels will be lit in a clockwise fashion. """ def __init__(self): # a dictionary of pixels as the key and # associated rgb color values self.pix_d = { 0: [153, 76, 0], 1: [153, 0, 0], 2: [153, 153, 0], 3: [204, 204, 0], 4: [0, 153, 0], 5: [0, 153, 153], 6: [0, 0, 233], 7: [153, 0, 153], 8: [255, 0, 255], 9: [255, 255, 255], } # save the previous pixel number that was illuminated self.last_pixel_used = 0 # instantiate pymatacpx self.p = PyMataCpx() # clear the pixels before monitoring the light # sensor values self.p.cpx_pixels_clear() # set pixel 0 to be the initial pixel and set its rgb # from the dictionary self.p.cpx_pixel_set(0, *self.pix_d[0]) self.p.cpx_pixels_show() # enable the light sensor and provide a callback. # Note: the callback is a member of this class. self.p.cpx_light_sensor_start(self.light_sensor_callback) print() print( 'Move a light source near the light sensor, and depending upon the' ) print( 'intensity of the light, an associated pixel will be illuminated.') print() while True: # just kill time waiting for a light data to arrive try: time.sleep(.1) except KeyboardInterrupt: # If you press control-C, cleanly exit self.p.cpx_close_and_exit() # This is the callback to process light sensor data def light_sensor_callback(self, data): """ Light sensor data processor :param data: data[2] contains the current light sensor reading :return: """ # get the currently reported level level = data[2] # the level is in the range of 0-1000. # adjust the level to map into a valid pixel number if level in range(0, 99): pixel = 0 elif level in range(100, 199): pixel = 1 elif level in range(200, 299): pixel = 2 elif level in range(300, 399): pixel = 3 elif level in range(400, 499): pixel = 4 elif level in range(500, 599): pixel = 5 elif level in range(600, 699): pixel = 6 elif level in range(700, 799): pixel = 7 elif level in range(800, 899): pixel = 8 else: pixel = 9 # get the rgb value for the pixel rgb = self.pix_d[pixel] # if this is not the same pixel as the last one enabled # then manipulate the pixels. # turn off the current pixel and turn on the new one. if pixel != self.last_pixel_used: # extinguish the previous pixel self.p.cpx_pixel_set(self.last_pixel_used, 0, 0, 0) # set the new pixel self.p.cpx_pixel_set(pixel, *rgb) # control the pixels self.p.cpx_pixels_show() self.last_pixel_used = pixel
class Thermometer: """ Touch the temperature sensor on the playground express. As the temperature increases, pixels will illuminate to indicate the temperature. """ def __init__(self): # a dictionary of pixels as the key and # associated rgb color values self.pix_d = { 0: [153, 76, 0], 1: [153, 0, 0], 2: [153, 153, 0], 3: [204, 204, 0], 4: [0, 153, 0], 5: [0, 153, 153], 6: [0, 0, 233], 7: [153, 0, 153], 8: [255, 0, 255], 9: [255, 255, 255], } # save the previous pixel number that was illuminated self.last_pixel_used = 0 # save the first temperature read as the ambient temperature # and use that as the basis of comparison. self.ambient = 0 # instantiate pymatacpx self.p = PyMataCpx() # clear the pixels before monitoring the light # sensor values self.p.cpx_pixels_clear() # set pixel 0 to be the initial pixel and set its rgb # from the dictionary self.p.cpx_pixel_set(0, *self.pix_d[0]) self.p.cpx_pixels_show() # enable the temperature sensor and provide a callback. self.p.cpx_temperature_start(self.temp_callback) print() print('Touch the temperature sensor. As the temperature changes') print('Different neopixels will light up.') print() print('The current temperature and pixel selected will be shown on the console.') print() while True: # just kill time waiting for a light data to arrive try: time.sleep(.1) except KeyboardInterrupt: # If you press control-C, cleanly exit self.p.cpx_close_and_exit() # This is the callback to process light sensor data def temp_callback(self, data): """ Light sensor data processor :param data: data[0] = 2 analog mode data[1] = pin 0 data[2] = temp in degrees C """ # the current temperature the_current_temperature = data[2] # save the temperature the first time # through as ambient if not self.ambient: self.ambient = the_current_temperature # select the pixel based on the current temperature if self.ambient < the_current_temperature < (self.ambient + .6): pixel = 0 elif (self.ambient + 0.6) < the_current_temperature < (self.ambient + 1.2): pixel = 1 elif (self.ambient < the_current_temperature + 1.2) < the_current_temperature < (self.ambient + 1.8): pixel = 2 elif (self.ambient < the_current_temperature + 1.8) < the_current_temperature < (self.ambient + 2.4): pixel = 3 elif (self.ambient < the_current_temperature + 2.4) < the_current_temperature < (self.ambient + 3.0): pixel = 4 elif (self.ambient < the_current_temperature + 3.0) < the_current_temperature < (self.ambient + 3.6): pixel = 5 elif (self.ambient < the_current_temperature + 3.6) < the_current_temperature < (self.ambient + 4.2): pixel = 6 elif (self.ambient < the_current_temperature + 4.2) < the_current_temperature < (self.ambient + 4.8): pixel = 7 elif (self.ambient < the_current_temperature + 4.8) < the_current_temperature < (self.ambient + 5.4): pixel = 8 else: pixel = 9 # get the rgb value for the pixel rgb = self.pix_d[pixel] # if this is not the same pixel as the last one enabled # then manipulate the pixels. # turn off the current pixel and turn on the new one. if pixel != self.last_pixel_used: # extinguish the previous pixel self.p.cpx_pixel_set(self.last_pixel_used, 0, 0, 0) # set the new pixel self.p.cpx_pixel_set(pixel, *rgb) # control the pixels self.p.cpx_pixels_show() self.last_pixel_used = pixel print('ambient: {} current: {} pixel{}'.format(round(self.ambient, 3), round(the_current_temperature, 3), pixel))
class CpxGateway(GatewayBase, threading.Thread): """ This class is the interface class for the Circuit Playground Express supporting Scratch 3. """ def __init__(self, *subscriber_list, back_plane_ip_address=None, subscriber_port='43125', publisher_port='43124', process_name='CpxGateway', publisher_topic=None, log=False): """ :param subscriber_list: a tuple or list of subscription topics. :param back_plane_ip_address: :param subscriber_port: :param publisher_port: :param process_name: """ # initialize parent super(CpxGateway, self).__init__(subscriber_list=subscriber_list, back_plane_ip_address=back_plane_ip_address, subscriber_port=subscriber_port, publisher_port=publisher_port, process_name=process_name) self.log = log if self.log: fn = str(pathlib.Path.home()) + "/cpxgw.log" self.logger = logging.getLogger(__name__) logging.basicConfig(filename=fn, filemode='w', level=logging.DEBUG) sys.excepthook = self.my_handler self.publisher_topic = publisher_topic self.cpx = PyMataCpx() atexit.register(self.shutdown) # hold the time of the last analog data to be received. # use to determine if connectivity is gone. self.last_analog_data_time = None # start up all the sensors self.cpx.cpx_accel_start(self.tilt_callback) self.cpx.cpx_button_a_start(self.switch_callback) self.cpx.cpx_button_b_start(self.switch_callback) self.cpx.cpx_slide_switch_start(self.switch_callback) self.cpx.cpx_light_sensor_start(self.analog_callback) self.cpx.cpx_microphone_start(self.analog_callback) self.cpx.cpx_temperature_start(self.analog_callback) for touch_pad in range(1, 8): self.cpx.cpx_cap_touch_start(touch_pad, self.touchpad_callback) threading.Thread.__init__(self) self.daemon = True # start the watchdog thread self.start() # start the banyan receive loop try: self.receive_loop() except: pass # except KeyboardInterrupt: # except KeyboardInterrupt: # self.cpx.cpx_close_and_exit() # sys.exit(0) # os._exit(1) def init_pins_dictionary(self): pass def play_tone(self, topic, payload): """ This method plays a tone on a piezo device connected to the selected pin at the frequency and duration requested. Frequency is in hz and duration in milliseconds. Call set_mode_tone before using this method. :param topic: message topic :param payload: {"command": "play_tone", "pin": “PIN”, "tag": "TAG", “freq”: ”FREQUENCY”, duration: “DURATION”} """ self.cpx.cpx_tone(payload['freq'], payload['duration']) def additional_banyan_messages(self, topic, payload): if payload['command'] == 'pixel': self.set_pixel(payload) def set_pixel(self, payload): self.cpx.cpx_pixel_set(payload['pixel'], payload['red'], payload['green'], payload['blue']) self.cpx.cpx_pixels_show() def digital_write(self, topic, payload): """ This method performs a digital write to the board LED :param topic: message topic :param payload: {"command": "digital_write", "pin": “PIN”, "value": “VALUE”} """ if payload['value']: self.cpx.cpx_board_light_on() else: self.cpx.cpx_board_light_off() # The CPX sensor callbacks def tilt_callback(self, data): """ Report the tilt of the express board Take the raw xyz data and transform it to positional strings. :param data: data [0] = data mode 32 is analog. data[1] = the pin number - this is a pseudo pin number data[2] = x value data[3] = y value data[4] = z value """ x = data[2] y = data[3] z = data[4] # Convert raw Accelerometer values to degrees x_angle = int((math.atan2(y, z) + math.pi) * (180 / math.pi)) y_angle = int((math.atan2(z, x) + math.pi) * (180 / math.pi)) h = v = -1 if 175 < x_angle < 185 and 265 < y_angle < 275: h = v = 0 # 'flat' elif h or v: if 180 <= x_angle <= 270: v = 1 # up elif 90 <= x_angle <= 180: v = 2 # down if 180 <= y_angle <= 270: h = 3 # left elif 270 <= y_angle <= 360: h = 4 # right payload = {'report': 'tilted', 'value': [v, h]} self.publish_payload(payload, 'from_cpx_gateway') def switch_callback(self, data): """ This handles switches a, b, and slide :param data: data[1] - a=4 b=5, slice=7, """ if data[1] == 4: switch = 'a' elif data[1] == 5: switch = 'b' else: # 0 = right, 1 = left switch = 'slide' payload = {'report': switch, 'value': data[2]} self.publish_payload(payload, 'from_cpx_gateway') def analog_callback(self, data): """ This handles the light, temperature and sound sensors. It also sets up a "watchdog timer" and if there is no activity for > 1 second will exit. :param data: data[1] - 8 = light, temp = 9, 10 = sound, """ self.last_analog_data_time = time.time() if data[1] == 8: sensor = 'light' elif data[1] == 9: sensor = 'temp' else: sensor = 'sound' payload = {'report': sensor, 'value': round(data[2], 2)} self.publish_payload(payload, 'from_cpx_gateway') def touchpad_callback(self, data): """ Build and send a banyan message for the pad and value :param data: data[1] = touchpad and data[2] = boolean value """ payload = {'report': 'touch' + str(data[1]), 'value': int(data[2])} self.publish_payload(payload, 'from_cpx_gateway') def shutdown(self): try: self.cpx.cpx_close_and_exit() sys.exit(0) except serial.serialutil.SerialException: pass def my_handler(self, xtype, value, tb): """ for logging uncaught exceptions :param xtype: :param value: :param tb: :return: """ self.logger.exception("Uncaught exception: {0}".format(str(value))) def run(self): if not self.last_analog_data_time: self.last_analog_data_time = time.time() while True: if time.time() - self.last_analog_data_time > 1.0: print('Watchdog timed out - exiting.') os._exit(1) time.sleep(1)
# create a cpx instance p = PyMataCpx() # enable all switches and attach all to the same callback p.cpx_button_a_start(buttons_callback) p.cpx_button_b_start(buttons_callback) p.cpx_slide_switch_start(buttons_callback) # Set pixel 6 initially on and 3 off. # If the switch is set to the left at start up # it will be detected and pixel 3 will be turned # on and pixel 6 turned off. p.cpx_pixel_set(6, 0, 0, 255) p.cpx_pixel_set(3, 0, 0, 0) p.cpx_pixels_show() print() print('Press Button A, Button B, Button A and B, or move the slide switch.') print( 'Each time you press a button or move the slide switch, the board LED will flash' ) print('and a neopixel will light indicating that button or slide switch') print('activation was processed and a message is printed to the console.') print() while True: # just kill time waiting for a switch change try: time.sleep(.1) except KeyboardInterrupt: