class Stop: ''' Create a object to store a stop with relation to its rgb pin mappings''' def __init__(self, name, arrival_time, red, green, blue): self.name = name self.arrival_time = arrival_time self.light = RGBLED(red, green, blue) self.colors = { 'red': (1, 0, 0), 'blue': (0, 0, 1), 'green': (0, 1, 0), 'yellow': (1, 1, 0), } def pulse(self, color): self.light.pulse(fade_in_time=.7, fade_out_time=.3, on_color=color, off_color=(0, 0, 0), background=True) return def color_decider(self): ''' Set light to be color/pulse depending on how long until the muni is coming''' self.light.on() if self.arrival_time in (0, 1, 2): self.pulse(self.colors['red']) elif self.arrival_time in (3, 4): self.pulse(self.colors['green']) elif self.arrival_time in (5, 6, 7, 8): self.light.color = self.colors['green'] elif self.arrival_time in (9, 10, 11, 12, 13, 14, 15): self.light.color = self.colors['yellow'] elif self.arrival_time > 15: self.light.color = self.colors['blue'] else: raise Exception( 'Unexpected else in color decider on arrival_time value: {}'. format(self.arriva_time)) return def cycle_colors(self): ''' Cycling colors indicates to users that the lights are updating ''' self.light.on() self.light.color = self.colors['red'] time.sleep(.5) self.light.color = self.colors['green'] time.sleep(.5) self.light.color = self.colors['blue'] time.sleep(.5) self.light.color = self.colors['yellow'] time.sleep(.5) self.light.off()
class CHFSM: # Normal operation IDLE_COLOUR = (1.5, 1.5, (0, 0, 0), (1.0, 1.0, 1.0)) # off to White CH_ONLY_COLOUR = (1.5, 1.5, (0, 0, 0), (0, 0.9, 0.4) ) # off to Reddy-purple HW_ONLY_COLOUR = (1.5, 1.5, (0, 0, 0), (0.9, 0.0, 0.1) ) # off to Greeny-cyan CH_AND_HW_COLOUR = (1.5, 1.5, (0, 0, 0), (0.9, 0.1, 0.0)) # off to Orange # INHIBIT_MODE = (1.5, 1.5, (0,0,0), (1, 0, 0.5)) # Off to purple # Errors NO_GATEWAY_CONNECTION = (1.5, 1.5, (1, 0, 0), (0.9, 0, 0.9) ) # Red to purple SCHEDULE_MISSING = (1.5, 1.5, (1, 0, 0), (1, 0.3, 0.0) ) # red to yellow/orange BAD_SCHEDULE = (1.5, 1.5, (1, 0, 0), (1, 1, 0)) # red to cyan # Maintainance mode BLUETOOTH_MODE = (1.5, 1.5, (0, 0, 1), (0, 1, 1)) # blue to cyan UPDATING = (1.5, 1.5, (0, 0, 1), (0, 1, 0)) #blue to Green update_time = config[r"update_time"] # Update and reboot time (day_of_month, hour, minute, second) UPDATE_REBOOT_TIME = (update_time["day_of_month"], update_time["hour"], update_time["minute"], update_time["second"]) PULSE_UP_TIME = 1.5 PULSE_DOWN_TIME = 1.5 BUTTON_BOUNCE_TIME = None # The duration of a CH or HW boost, in seconds BOOST_DURATION = config["boost_duration"] def __init__(self, red, green, blue, hw_relay, ch_relay, hw_button, ch_button, rgb_active_high, ch_relay_active_high, hw_relay_active_high): # Setup push buttons self.ch_button = BetterButton(ch_button, self.chPressed, self.BUTTON_BOUNCE_TIME, None, True) self.hw_button = BetterButton(hw_button, self.hwPressed, self.BUTTON_BOUNCE_TIME, None, True) # Setup relay self.hw_relay = DigitalOutputDevice(hw_relay, hw_relay_active_high) self.ch_relay = DigitalOutputDevice(ch_relay, ch_relay_active_high) # Setup RGB status LED self.status_led = RGBLED(red, green, blue, active_high=rgb_active_high) self.commands_file_path = config["commands_path"] self.schedule_file_path = config["schedule_path"] # Setup HW boost objects self.hw_boost_start = None self.ch_boost_on = False self.hw_pressed_flag = False self.ch_pressed_flag = False # Load first state self.state = IdleState(self) self.state.enter() # self.last_gateway_ping = datetime.now() def close(self): self.status_led.close() self.hw_relay.close() self.ch_relay.close() def setState(self, state): self.state.leave() self.state = state logging.debug("State change: %s", type(state)) self.state.enter() def process(self): self.state.process() def getState(self): return self.state def chPressed(self): logging.debug("CH button press") self.ch_pressed_flag = True def hwPressed(self): logging.debug("HW button press") self.hw_pressed_flag = True def setStatusLed(self, colour): self.status_led.pulse(colour[0], colour[1], off_color=colour[2], on_color=colour[3]) def parent_folder(): return os.path.dirname(os.path.dirname(__file__))
# Import libraries import RPi.GPIO as GPIO from time import sleep from signal import pause from gpiozero import RGBLED # Write all codes inside try statement try: led = RGBLED( 17, 27, 22, active_high=False) # Set active_high to False for common anode led.pulse(on_color=(0.1, 0.3, 0.4)) pause() # except statement to handle user's keyboard interrupt except KeyboardInterrupt: print("Stopping python script...") print("Cleaning up GPIO...") # finally statement will run before exiting try statement finally: GPIO.cleanup() print("Cleaning completed!") print("Exit program")
class LED: def __init__(self, red, green, blue, verbose=False): self.led = RGBLED(red, green, blue) self.bright = 1 self.thread = Thread() self.stop_thread = False self.verbose = verbose if AUTODIM: t = Thread(target=self.autoDimming, daemon=True) t.start() self.changeLights(LightChanges.instant, DEFAULT_COLOR) self.dprint('lights init') def handle(self, payload): #kill old thread self.killThread() #handle brightness if payload in LED_bright_terms: self.dprint('brightness to {}'.format(payload)) self.bright = LED_bright_terms[payload] self.changeLights(self.change_type, self.color) return True change_type = LightChanges.transition #handle toggle/on/off/stop if payload == 'toggle': self.dprint('toggle') if self.led.is_lit: self.led.off() else: self.changeLights(change_type, self.color) return True if payload == 'off': self.dprint('off') self.led.off() return True if payload == 'on': self.dprint('on') self.changeLights(change_type, self.color) return True if payload == 'stop': self.dprint('stop') self.led.color = self.led.color return True color = payload if 'pulse' in payload: color = payload.replace('pulse', '').replace(' ', '') if color == '': color = self.color change_type = LightChanges.pulse elif 'rain' in payload: color = 'black' change_type = LightChanges.rainbow #handle color self.thread = Thread(target=self.changeLights, args=(change_type, color), daemon=True) self.thread.start() return True def changeLights(self, type, colortext='black'): try: color = Color(colortext) except ValueError: self.dprint('error while trying to parse {}'.format(colortext)) return False self.dprint('change type {} to {}{}{}'.format(type, color, color.rgb, Color('white'))) self.change_type = type switcher = { LightChanges.instant: self.setColor, LightChanges.transition: self.chgTrans, LightChanges.pulse: self.chgPulse, LightChanges.rainbow: self.chgRain } switcher.get(type, lambda x: self.dprint('invalid input'))(color) return True def setColor(self, color, ignore_bright=False): self.color = color self.led.color = self.applyBright( color) if ignore_bright is False else color self.dprint('set color to {}{}{}'.format(color, color.rgb, Color('white'))) def applyBright(self, color): if self.bright == 1: return color else: return Color(tuple(self.bright * x for x in color)) def chgTrans(self, new_color, ignore_bright=False, duration=TRANSITION_DURATION): N = REFRESH_RATE * duration #total color difference diff = [] for n, c in zip(new_color, self.led.color): diff.append(n - c) self.color = self.led.color #color change per update step = tuple(x / N for x in diff) for _ in range(N - 1): step_color = [] for c, s in zip(self.color, step): step_color.append(c + s) self.setColor(Color(tuple(step_color)), ignore_bright) sleep(1 / REFRESH_RATE) self.setColor(new_color, ignore_bright) def chgPulse(self, color): self.dprint('pulsing on {}{}{}'.format(color, color.rgb, Color('white'))) color = self.applyBright(color) self.led.pulse(fade_in_time=FADE_DURATION, fade_out_time=FADE_DURATION, on_color=color) def chgRain(self, _): self.dprint('running rainbow') freq1, freq2, freq3 = .03, .03, .03 ph1, ph2, ph3 = 0, 2, 4 center, width = 128, 127 #center, width = 230, 25 #for pastels length = 200 while self.stop_thread is not True: for i in range(length): if self.stop_thread is True: break red = sin(freq1 * i + ph1) * width + center green = sin(freq2 * i + ph2) * width + center blue = sin(freq3 * i + ph3) * width + center self.setColor(Color(red, green, blue)) sleep((1 / REFRESH_RATE) * 2) def autoDimming(self): last_dimmed_day = 0 last_undimmed_day = 0 while True: dt = datetime.now() if (last_dimmed_day != dt.day) and (DIM_START_HOUR <= dt.hour < DIM_END_HOUR) and self.bright != 0.25: self.dprint('auto-dimming') last_dimmed_day = dt.day self.bright = 0.25 elif (last_undimmed_day != dt.day) and ( dt.hour < DIM_START_HOUR or dt.hour >= DIM_END_HOUR) and self.bright != 1: self.dprint('auto-undimming') last_undimmed_day = dt.day self.bright = 1 else: sleep(60) continue if self.led.is_lit: self.killThread() if self.change_type == LightChanges.transition: self.chgTrans(applyBright(self.color), ignore_bright=True, duration=3) else: self.changeLights(self.change_type, self.color) sleep(60) def killThread(self): if self.thread.is_alive() is not True: return self.dprint('stop thread') self.stop_thread = True self.thread.join() self.stop_thread = False def dprint(self, text): if self.verbose: print(text)
# control buttons #TODO: possible support for multiple light racks in future? apply = Button(21) kill = Button(20) print("PROGRAM ACTIVE") red.off() green.off() blue.off() selectionLED.color = (0, 0, 0) while kill.is_pressed == False: #TODO: add in support for lightRelays1 selectionLED.pulse(1, 1, (0, 0, 1)) #blue blue.on() apply.wait_for_press() selectionLED.off() blue.off() apply.wait_for_release() selectionLED.pulse(1, 1, (0, 1, 0)) #green green.on() apply.wait_for_press() selectionLED.off() green.off() apply.wait_for_release() selectionLED.pulse(1, 1, (0, 1, 1)) #teal green.on()
class AlertHarness: def __init__(self, args): if args.test or args.replay: self.radio = None else: r = self.radio = rf95.RF95(cs=RF95_SPI_CS, int_pin=RF95_IRQ_PIN, reset_pin=RF95_RESET_PIN) assert r.init(), "failed to intialize radio" r.set_modem_config(rf95.Bw125Cr45Sf128) r.set_frequency(RF95_FREQ) self._args = args self.log_handle = open(args.log, 'w') if args.log else None self.replay_handle = open(args.replay, 'r') if args.replay else None self._pending_line = None self._time_offset = 0 if self.replay_handle: if self.read_replay_line(): self._time_offset = time.time() - self._pending_line[0] self.test = args.test self.use_tts = args.tts self.use_alarm = args.alarm self.numbers = args.phone self.emails = args.email self.stopping = False self.led = RGBLED(*RGBLED_PINS) self.lcd_thread = LCDThread(SEGMENT_PINS, DIGIT_PINS) self.trouble_tags = set() self.known_tags = set() self.monitor_thread = BackgroundThread(self.status_loop, start=False) self.announce_thread = None self._buzzer = False if twilio is not None: self.twilio_client = TwilioClient(TWILIO_SID, TWILIO_AUTH) else: self.twilio_client = None if sendgrid is not None: self.mail_client = sendgrid.SendGridAPIClient(apikey=SENDGRID_API_KEY) else: self.mail_client = None self.conn = None self.states = StateTracker() def read_replay_line(self) -> bool: try: line = next(self.replay_handle) ts, rssi, pkt_hex = line.split(",") ts = float(ts.strip()) rssi = float(rssi.strip()) pkt = bytes.fromhex(pkt_hex.strip()) self._pending_line = ts, rssi, pkt return True except (StopIteration, ValueError): self._pending_line = None return False def set_plotter(self, address: str, port: int = PLT_DEFAULT_PORT): if isinstance(port, str): port = int(port) elif port is None: port = PLT_DEFAULT_PORT self.conn = mpClient((address, port)) def send_sms(self, body: str): if self.twilio_client is None or not self.numbers: return False ret = [] for number in self.numbers: msg = self.twilio_client.messages.create(to=number, from_=TWILIO_NUMBER, body=body) ret.append(msg) return ret def send_email(self, subject: str, body: str): if self.mail_client is None or not self.emails: return False personalization = Personalization() for email in self.emails: email = Email(email) personalization.add_to(email) from_email = Email(SENDGRID_FROM_ADDRESS) content = Content("text/plain", body) mail = Mail(from_email, subject, None, content) mail.add_personalization(personalization) return self.mail_client.client.mail.send.post(request_body=mail.get()) def get_packet(self, timeout=None) -> Optional[RadioPacket]: packet = None if self.test: return elif self.replay_handle: packet = self.replay_packet(timeout) elif self.radio: start = time.time() while not self.radio.available(): sleep(0.005) if timeout and (time.time() - start > timeout): return rxbuf = self.radio.recv() rxbuf = bytes(rxbuf[4:]) # skip flag rssi = self.radio.last_rssi try: packet = RadioPacket.from_bytes(rxbuf, rssi, timestamp=time.time()) except Exception as e: h = rxbuf.hex() hexstr = ' '.join(h[x:x + 2] for x in range(0, len(h), 2)) new_e = RuntimeError("error parsing packet with length %d and data:\n%s" % (len(rxbuf), hexstr)) raise new_e from e if packet: self.states.update(packet) return packet def replay_packet(self, timeout=None): if self._pending_line: target = self._pending_line[0] + self._time_offset sleep_for = target - time.time() if timeout and sleep_for > timeout: sleep(timeout) return None else: sleep(max(0, sleep_for)) timestamp, rssi, rxbuf = self._pending_line timestamp = target if not self.read_replay_line(): print("end of log, stopping") self.stopping = True return RadioPacket.from_bytes(rxbuf, rssi, timestamp=timestamp) def run_test(self): print("Test mode: will simulate an alert in 10 seconds") sleep(10) self.show_alert(42) print("Test mode: returning to normal in 10 seconds") sleep(10) self.clear_alert() print("Test mode: will exit in 5 seconds") sleep(5) def run(self): # Initialize everything as OK self.clear_alert() self.monitor_thread.start() self.lcd_thread.start() if self.test: return self.run_test() while not self.stopping: try: packet = self.get_packet(timeout=1) if not packet: continue if self.conn: self.conn.send((packet.raw, packet.rssi, packet.timestamp)) if self.log_handle: line = '%s,%s,%s' % (packet.timestamp, packet.rssi, packet.raw.hex()) self.log_handle.write(line + '\n') # print(packet.serial, packet.seq, packet.orientation, packet.rssi, packet.vbatt) # pprint(packet.samples[-1]) self.known_tags.add(packet.tag) if self.states.state_for(packet.tag) is State.DISTRESS: if packet.tag not in self.trouble_tags: self.trouble_tags.add(packet.tag) self.show_alert(packet.tag) elif packet.tag in self.trouble_tags: self.trouble_tags.remove(packet.tag) self.clear_alert() except Exception: traceback.print_exc() def status_loop(self): while not self.stopping: for i in range(int(ACTIVE_SLEEP / 0.01)): sleep(0.01) if self.stopping: break tag_strs = ['%d: %s' % (t, self.states.state_for(t).name.lower()) for t in self.known_tags] print("Active tags:\n%s" % ('\n'.join(tag_strs) or '(none)')) def show_alert(self, tag: int): print("showing alert for tag", tag) self.lcd_thread.set_value(tag) self.led.pulse(on_color=RED) msg = "Tag %s is in distress!" % tag self.announce_msg = msg self.announce() self.send_email("Bovine Intervention alert", msg) self.send_sms("Bovine Intervention alert: " + msg) def clear_alert(self): print("clearing alert") self.led.blink(on_color=GREEN, on_time=0.05, off_time=5 - 0.05) self.lcd_thread.clear() self.announce_msg = None if self.announce_thread: self.announce_thread.stop() # block def announce_cb(self, result): if self.announce_msg is None or self.stopping: # reset to None self.announce_thread = None self._buzzer = False elif self._buzzer: self._buzzer = False self.announce_thread = CommandThread([TTS_SCRIPT, self.announce_msg], self.announce_cb) else: self._buzzer = True self.announce_thread = CommandThread(["mplayer", "-really-quiet", ALARM_SOUND], self.announce_cb) def announce(self): if self.announce_thread: self.announce_thread.join() # block self.announce_thread = CommandThread(["mplayer", ALARM_SOUND], self.announce_cb) self._buzzer = True def shutdown(self): self.stopping = True self.lcd_thread.stop() self.monitor_thread.join() self.led.close() #GPIO.cleanup() if self.announce_thread: self.announce_thread.stop() if self.radio: self.radio.cleanup() if self.log_handle: self.log_handle.close() if self.replay_handle: self.replay_handle.close()
class ILedStrip(object): """ Interface to GPIOZERO RGBLED Adds support for Hex and Generic words such as: "none", "red", "green", "blue", "purple", "yellow" "aqua", "orange", "magenta", "white" """ def __init__(self, red, green, blue): """ sets up the Interface Args: red (int): GPIO Pin green (int): GPIO pin blue (int): GPIO Pin """ self._led_strip = RGBLED(red, green, blue) self._cur_color = "#0000FF" self._prev_color = "#0000FF" self._is_pulse = False self._defined_colors = { "none": "#000000", "red": "#FF0000", "green": "#00FF00", "blue": "#0000FF", "purple": "#FF00FF", "yellow": "#FFFF00", "aqua": "#00FFFF", "orange": "#FF1000", "magenta": "#FF0080", "white": "#FFFFFF" } # Setter def set_on(self): """ Turns RGB on sets to the defined color """ self._is_pulse = False self._led_strip.color = self._cvt_hex(self._cur_color) # Setter def set_off(self): """ Turns RGB off """ self._is_pulse = False self._led_strip.off() # Setter def set_color_hex(self, color="#000000"): """ Sets the color to hex or sets it to none if not valid hex """ if self._is_valid_hex(color): self._led_strip.color = self._cvt_hex(color) self._prev_color = self._cur_color self._is_pulse = False self._cur_color = color # Setter def set_color_word(self, color="none"): """ Set color to current word or sets it to none if it is not supported """ self._led_strip.color = self._color_map(color) self._prev_color = self._cur_color self._is_pulse = False self._cur_color = self._color_map(color, return_tuple=False) # Getter def get_status(self): """ returns if the led_strip is lit """ if self._is_pulse: return True return self._led_strip.is_lit def get_pulse_status(self): """ returns true if currently pulsing """ return self._is_pulse def get_prev_color(self): """ returns previous color """ return self._color_map(self._prev_color, return_tuple=False) # Getter def get_defined_colors(self): """ returns what colors are supported and which color it is currently set to """ defined_colors = {} for color in self._defined_colors: hex_color = self._color_map(color, return_tuple=False) if hex_color == self._cur_color: defined_colors[color] = True else: defined_colors[color] = False return defined_colors def toggle(self): """ Toggles between off and on """ if not self.led_strip.is_lit: self.set_on() else: self.set_off() def pulse(self, fade_in_time=5, fade_out_time=5, off_color=(0, 0, 0)): on_color = self._cvt_hex(self._cur_color) self._is_pulse = True self._led_strip.pulse(fade_in_time=fade_in_time, fade_out_time=fade_out_time, on_color=on_color, off_color=off_color) def blue2red(self): self._led_strip.pulse(fade_in_time=10, fade_out_time=10, on_color=(1, 0, 0), off_color=(0, 0, 1)) def _cvt_hex(self, colorInHex): """ TODO: make this more reslient """ try: red = float(int(colorInHex[1:3], 16)) / 255 green = float(int(colorInHex[3:5], 16)) / 255 blue = float(int(colorInHex[5:], 16)) / 255 return (red, green, blue) except: return self._cvt_hex(self._cur_color) LOGGER.debug("Exception in cvtHex") def _color_map(self, color, return_tuple=True): if return_tuple: return self._cvt_hex(self._defined_colors.get(color, "#000000")) else: return self._defined_colors.get(color, "#000000") def _is_valid_hex(self, colorInHex): _rgbstring = re.compile(r'#[a-fA-F0-9]{6}$') return bool(_rgbstring.match(colorInHex))
class bbrun: # BBEnc encryption object bbenc = None # PN532 Scanner object bbsc = None # PN532 object #Coffee Maker Database Setup DATABASE = r'blackbean.db' DATAPATH = r'' bbdb = None # sqlite object #TFT Display Setup - ST7789 Adafruit 240x240 1.54" SPI PIN_DC = 24 PIN_RST = 23 SPI_PORT = 0 SPI_DEVICE = 0 disp = None # Solid State Relay Setup - Omron PIN_RELAY = 26 relay = None # RGB LED Setup - Note CA LED: values reversed, led.On() turns OFF led PIN_RED = 5 PIN_GREEN = 6 PIN_BLUE = 4 C_GREEN = (1,0.5,1) C_TEAL = (1,0.8,0.5) T_PULSE = 0.5 led = None # Last scan array - to be used by functions in bbrun lastscan = None def __init__(self): self.led = RGBLED(self.PIN_RED, self.PIN_GREEN, self.PIN_BLUE) self.led.value = (1,1,0) self.relay = LED(self.PIN_RELAY) # Create TFT LCD display class. self.disp = TFT.ST7789(self.PIN_DC, rst=self.PIN_RST, \ spi=SPI.SpiDev(self.SPI_PORT, self.SPI_DEVICE, \ max_speed_hz=64000000)) # Initialize display. self.disp.begin() # Clear the display to a red background. # Can pass any tuple of blue, green, red values (from 0 to 255 each). self.disp.clear((255, 0, 0)) # Initialize blackbean database class self.bbdb = bbsql.bbdb(self.DATAPATH, self.DATABASE) # Initialize PN532 RFID class self.bbsc = bbscan.bbscan() print(self.bbsc.resp) # Initialize encryption class self.bbenc = bbenc.bbenc() self.bbenc.load_public() print(self.bbenc.resp) def LedDemo(self): self.led.pulse(self.T_PULSE, self.T_PULSE, self.C_TEAL, self.C_GREEN) sleep(10) def RelayDemo(self): self.relay.blink(1) sleep(10) def TftDemo(self): # Get a PIL Draw object to start drawing on the display buffer. draw = self.disp.draw() # Draw a cyan triangle with a black outline. draw.polygon( [(10, 275), (110, 240), (110, 310)], outline=(0,0,0), \ fill=(0,255,255)) # Load default font. font = ImageFont.load_default() # Write two lines of white text on the buffer, rotated 90 degrees counter clockwise. self.DrawRotatedText(self.disp.buffer, 'Hello World!', (150, 120), \ 90, font, fill=(255,255,255)) self.DrawRotatedText(self.disp.buffer, 'This is a line of text.', \ (170, 90), 90, font, fill=(255,255,255)) # Write buffer to display hardware, must be called to make things visible on the # display! self.disp.display() def RelayOn(self): self.relay.on() def RelayOff(self): self.relay.off() def LedColor(self, rgb=(1,1,1)): self.led.value = rgb # Define a function to create rotated text. Unfortunately PIL doesn't have good # native support for rotated fonts, but this function can be used to make a # text image and rotate it so it's easy to paste in the buffer. def DrawRotatedText(self, image, text, position, angle, font, \ fill=(255,255,255)): # Get rendered font width and height. draw = ImageDraw.Draw(image) width, height = draw.textsize(text, font=font) # Create a new image with transparent background to store the text. textimage = Image.new('RGBA', (width, height), (0,0,0,0)) # Render the text. textdraw = ImageDraw.Draw(textimage) textdraw.text((0,0), text, font=font, fill=fill) # Rotate the text image. rotated = textimage.rotate(angle, expand=1) # Paste the text into the image, using it as a mask for transparency. image.paste(rotated, position, rotated) # Display Fortune def DrawFortune(self, fortune): font = ImageFont.truetype('Momt___.ttf',22) angle = 0 self.disp.buffer.paste((0,0,0), (0,0,240,240)) length = len(fortune) # number of characters CHARLINEMAX = 16 LINEMAX = 10 LINESPACE = 20 XSTART = 10 YSTART = 10 FILL = (255,255,255) lines = textwrap.wrap(fortune, CHARLINEMAX, break_long_words=False) x = XSTART y = YSTART for line in lines: self.DrawRotatedText( \ self.disp.buffer, line, (x,y), angle, font, fill=FILL) y = y + LINESPACE self.disp.display() # Display Image def DisplayImage(self, dirname, imagename): image = Image.open(dirname+"/"+imagename) #assume 240x240 self.disp.display(image) # assume angle 0 # Display Homescreen def DrawHome(self): font = ImageFont.truetype('Play With Fire.ttf',42) fonttwo = ImageFont.truetype('Momt___.ttf',22) angle = 0 self.disp.buffer.paste((0,0,0), (0, 0, 240, 240)) self.DrawRotatedText( \ self.disp.buffer, 'Coffee', (10, 10), angle, font, fill=(255,255,255)) self.DrawRotatedText(\ self.disp.buffer, 'Club', (10, 70), angle, font, fill=(255,255,255)) self.DrawRotatedText(\ self.disp.buffer, 'Scan Badge', (10, 180), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'Get Coffee', (10, 200), angle, fonttwo, fill=(230,230,230)) self.disp.display() # Display Brewscreen def DrawBrew(self): font = ImageFont.truetype('Play With Fire.ttf',42) fonttwo = ImageFont.truetype('Momt___.ttf',22) angle = 0 self.disp.buffer.paste((0,0,0), (0, 0, 240, 240)) self.DrawRotatedText( \ self.disp.buffer, 'Brewing', (10, 10), angle, font, fill=(0,255,0)) self.DrawRotatedText(\ self.disp.buffer, 'Yum yum!', (10, 90), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'Issues?', (10, 130), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'Check help sheet', (10, 150), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'or contact Chris', (10, 170), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'Wallace', (10, 190), angle, fonttwo, fill=(230,230,230)) self.disp.display() # Display Deniedscreen def DrawDenied(self): font = ImageFont.truetype('Play With Fire.ttf',42) fonttwo = ImageFont.truetype('Momt___.ttf',22) angle = 0 self.disp.buffer.paste((0,0,0), (0, 0, 240, 240)) self.DrawRotatedText( \ self.disp.buffer, 'Sorry', (10, 10), angle, font, fill=(0,0,255)) self.DrawRotatedText(\ self.disp.buffer, 'Badge not', (10, 90), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'recognized. To', (10, 110), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'join the coffee', (10, 130), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'club contact', (10, 150), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'Shaun Bowman', (10, 170), angle, fonttwo, fill=(230,230,230)) self.disp.display() # Display Adminscreen def DrawAdminIp(self,ipString): font = ImageFont.truetype('Play With Fire.ttf',42) fonttwo = ImageFont.truetype('MAGIMTOS.ttf',32) angle = 0 self.disp.buffer.paste((50,0,0), (0, 0, 240, 240)) self.DrawRotatedText( \ self.disp.buffer, 'IP:', (10, 10), angle, font, fill=(200,0,50)) ipString = ipString.split('.') self.DrawRotatedText( \ self.disp.buffer, ipString[0], (10, 80), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText( \ self.disp.buffer, ipString[1], (10, 115), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText( \ self.disp.buffer, ipString[2], (10, 150), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText( \ self.disp.buffer, ipString[3], (10, 185), angle, fonttwo, fill=(230,230,230)) self.disp.display() # Display Adminscreen def DrawAdmin(self): font = ImageFont.truetype('Play With Fire.ttf',42) fonttwo = ImageFont.truetype('MAGIMTOS.ttf',32) angle = 0 self.disp.buffer.paste((50,0,0), (0, 0, 240, 240)) self.DrawRotatedText( \ self.disp.buffer, 'Admin', (10, 10), angle, font, fill=(200,0,50)) self.DrawRotatedText(\ self.disp.buffer, '1 Add', (10, 70), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, '2 Remove', (10, 110), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, '3 Stats', (10, 150), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, '4 Exit', (10, 190), angle, fonttwo, fill=(230,230,230)) self.disp.display() # Display Addscreen def DrawAdd(self): font = ImageFont.truetype('Play With Fire.ttf',42) fonttwo = ImageFont.truetype('MAGIMTOS.ttf',32) angle = 0 self.disp.buffer.paste((50,0,0), (0, 0, 240, 240)) self.DrawRotatedText( \ self.disp.buffer, 'Admin', (10, 10), angle, font, fill=(200,0,50)) self.DrawRotatedText(\ self.disp.buffer, 'scan', (10, 70), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'first', (10, 110), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'last', (10, 150), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, '4 Exit', (10, 190), angle, fonttwo, fill=(230,230,230)) self.disp.display() # Display Removescreen def DrawRemove(self): font = ImageFont.truetype('Play With Fire.ttf',42) fonttwo = ImageFont.truetype('MAGIMTOS.ttf',32) angle = 0 self.disp.buffer.paste((50,0,0), (0, 0, 240, 240)) self.DrawRotatedText( \ self.disp.buffer, 'Admin', (10, 10), angle, font, fill=(200,0,50)) self.DrawRotatedText(\ self.disp.buffer, 'first', (10, 70), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, 'last', (10, 110), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, '3 Remove', (10, 150), angle, fonttwo, fill=(230,230,230)) self.DrawRotatedText(\ self.disp.buffer, '4 Exit', (10, 190), angle, fonttwo, fill=(230,230,230)) self.disp.display() # Draw Recieved def DrawRecieved(self, x, y): font = ImageFont.truetype('arrow_7.ttf',42) angle = 0 char = '&' self.DrawRotatedText( \ self.disp.buffer, char, (x, y), angle, font, fill=(200,0,50)) self.disp.display() # Standbye Pulse def LedStandby(self): T_PULSE = 2 self.led.pulse(T_PULSE, T_PULSE, self.C_TEAL, self.C_GREEN) # Brew Pulse def LedBrew(self): T_PULSE = 0.5 COLOR_ON = (1,0,1) COLOR_OFF = (1,1,1) self.led.pulse(T_PULSE, T_PULSE, COLOR_ON, COLOR_OFF) # Denied Pulse def LedDenied(self): T_PULSE = 0.5 COLOR_ON = (0,1,1) COLOR_OFF = (1,1,1) self.led.pulse(T_PULSE, T_PULSE, COLOR_ON, COLOR_OFF) # Admin Pulse def LedAdmin(self): T_PULSE = 0.1 COLOR_ON = (1,1,0.5) COLOR_OFF = (0.5,1,0.5) self.led.pulse(T_PULSE, T_PULSE, COLOR_ON, COLOR_OFF)
led2.on() led3.on() button.wait_for_press() button.wait_for_release() led1.blink() sleep(0.4) led2.blink() sleep(0.4) led3.blink() button.wait_for_press() button.wait_for_release() led1.pulse() sleep(0.4) led2.pulse() sleep(0.4) led3.pulse() button.wait_for_press() button.wait_for_release() led1.on() led2.color(mode1) led3.color(mode2) button.wait_for_press() button.wait_for_release()
class Beacon(object): connectState = ConnectState.Disconnected failConnectCount = 0 configData = None commandsData = None client = None soundDir = os.path.join(launchDir, 'sounds/') rgbLED = None button = None buttonHoldTime = None persistentLedRule = None def __init__(self): logging.info("Beacon service initialized") with open(os.path.join(launchDir, 'beacon.json')) as data_file: self.configData = json.load(data_file) #need to account for no json data loaded if (self.configData.get("gpio")): gpioData = self.configData["gpio"] if gpioData.get("button"): self.button = Button(int(gpioData["button"])) self.button.when_released = self.buttonReleased self.button.when_held = self.buttonHeld else: logging.error( "config json gpio object missing required button id") if gpioData.get("red_led") and gpioData.get( "green_led") and gpioData.get("blue_led"): self.rgbLED = RGBLED(int(gpioData["red_led"]), int(gpioData["green_led"]), int(gpioData["blue_led"]), False, (0, 0, 0), True) else: logging.error( "config json gpio object missing required redled, greenled, and blueled ids" ) else: logging.error("config json missing require gpio object") if self.configData.get("directories"): dirObj = self.configData["directories"] if dirObj.get("sound"): soundDir = dirObj["sound"] if self.configData.get("commands"): self.commandsData = self.configData["commands"] self.ledDisplay(LedDisplayRule(0, 1, 0, 1, 1)) sleep(1) self.client = MQTTClient(self.configData["credentials"]["username"], self.configData["credentials"]["key"]) self.client.on_connect = self.connected self.client.on_disconnect = self.disconnected self.client.on_message = self.message while True: if self.connectState == ConnectState.Disconnected: self.connect() elif self.connectState == ConnectState.PendingReconnect: self.reconnect() try: self.client.loop() except RuntimeError: logging.exception("runtime error caught from mqtt client loop") self.reconnect() def buttonHeld(self): self.buttonHoldTime = time.time() def buttonReleased(self): if self.buttonHoldTime is not None: heldTime = time.time() - self.buttonHoldTime + 1 self.buttonHoldTime = None print heldTime if heldTime > 5: self.ledDisplay(LedDisplayRule(1, 0, 0, 3, .5)) sleep(2) self.stopLED() os.system('sudo shutdown -r now') else: self.stopLED() self.persistentLedRule = None print self.commandsData if mixer.get_init() and mixer.music.get_busy(): mixer.music.stop() mixer.quit() elif self.commandsData is not None: self.client.publish(self.configData["feeds"]["outbound"], self.commandsData[0]) def message(self, client, feed_id, payload): msgStr = 'Feed {0} received new value: {1}'.format(feed_id, payload) log_data = "" with open(logFilePath, 'r') as myfile: log_data = myfile.read().replace('\n', '') if log_data.find(msgStr) == -1 or testing: logging.info(msgStr) messageData = None try: messageData = json.loads(payload) except: pass sound = None volume = 1 redVal = 0 greenVal = 1 blueVal = 0 blinkCount = 1 blinkRate = 1 persistent = False pulse = False if self.configData.get("sounds"): sound = self.configData["sounds"]["default"] if messageData is not None: if messageData.get("sound"): sound = self.configData["sounds"][messageData["sound"]] if messageData.get("persistent") and str( messageData["persistent"]).lower() == "true": persistent = True if messageData.get("volume") is not None: volume = float(messageData.get("volume")) if messageData.get("blinkCount") is not None: blinkCount = int(messageData.get("blinkCount")) if messageData.get("blinkRate") is not None: blinkRate = float(messageData.get("blinkRate")) if messageData.get("pulse") is not None and str( messageData["pulse"]).lower() == "true": pulse = True if messageData.get("color") is not None: try: colorArr = str(messageData.get("color")).split("/") redVal = float(colorArr[0]) greenVal = float(colorArr[1]) blueVal = float(colorArr[2]) except: pass if sound is not None: mixer.init() mixer.music.set_volume(volume) mixer.music.load(self.soundDir + sound) mixer.music.play() self.ledDisplay( LedDisplayRule(redVal, greenVal, blueVal, blinkCount, blinkRate, pulse, persistent)) def stopLED(self): self.rgbLED._stop_blink() self.rgbLED.off() def ledDisplay(self, rule): self.stopLED() blinkCount = rule.blinkCount if (rule.persistent): blinkCount = None self.persistentLedRule = rule if (rule.pulse): self.rgbLED.pulse(fade_in_time=rule.blinkRate, fade_out_time=rule.blinkRate, on_color=(rule.r, rule.g, rule.b), off_color=(0, 0, 0), n=blinkCount, background=True) else: self.rgbLED.blink(on_time=rule.blinkRate, off_time=rule.blinkRate, fade_in_time=0, fade_out_time=0, on_color=(rule.r, rule.g, rule.b), off_color=(0, 0, 0), n=blinkCount, background=True) def connected(self, client): logging.info("Connected to Adafruit IO") self.connectState = ConnectState.Connected self.failConnectCount = 0 self.client.subscribe(self.configData["feeds"]["inbound"]) def disconnected(self, client): logging.info('Disconnected from AdafruitIO') self.connectState = ConnectState.Disconnected self.reconnect() def connect(self): logging.info("init connect to Adafruit IO") self.connectState = ConnectState.Connecting try: self.client.connect() except Exception as e: logging.exception("Exception from Adafruit client connect") self.reconnect() def reconnect(self): self.failConnectCount += 1 logging.info('pending Adafruit IO reconnect - failcount=' + str(self.failConnectCount)) self.connectState = ConnectState.Connecting sleep(10) self.connect()
while 1: current_time = datetime.now() fsm.process() diag.process() sleep(TICK_DURATION) except Exception as e: logging.exception("Unhandled exception - '%s'", str(e)) # Close all previous GPIO devices fsm.close() # Turn relays off hw = DigitalOutputDevice(HW_RELAY_PIN, HW_RELAY_ACTIVE_HIGH) ch = DigitalOutputDevice(CH_RELAY_PIN, CH_RELAY_ACTIVE_HIGH) hw.off() ch.off() # Put RGB LED on pulsing red rgb_led = RGBLED(RED_LED_PIN, GREEN_LED_PIN, BLUE_LED_PIN, active_high=RGB_ACTIVE_HIGH) rgb_led.pulse(1.5, 1.5, on_color=(1, 0, 0))