|
| 1 | +import board |
| 2 | +import displayio |
| 3 | +import busio |
| 4 | +from digitalio import DigitalInOut |
| 5 | +from analogio import AnalogIn |
| 6 | +import neopixel |
| 7 | +import adafruit_adt7410 |
| 8 | +from adafruit_esp32spi import adafruit_esp32spi |
| 9 | +from adafruit_esp32spi import adafruit_esp32spi_wifimanager |
| 10 | +import adafruit_esp32spi.adafruit_esp32spi_socket as socket |
| 11 | +from adafruit_bitmap_font import bitmap_font |
| 12 | +from adafruit_display_text.label import Label |
| 13 | +from adafruit_button import Button |
| 14 | +import adafruit_touchscreen |
| 15 | +from adafruit_minimqtt import MQTT |
| 16 | + |
| 17 | +# ------------- WiFi ------------- # |
| 18 | + |
| 19 | +# Get wifi details and more from a secrets.py file |
| 20 | +try: |
| 21 | + from secrets import secrets |
| 22 | +except ImportError: |
| 23 | + print("WiFi secrets are kept in secrets.py, please add them there!") |
| 24 | + raise |
| 25 | + |
| 26 | +# If you are using a board with pre-defined ESP32 Pins: |
| 27 | +esp32_cs = DigitalInOut(board.ESP_CS) |
| 28 | +esp32_ready = DigitalInOut(board.ESP_BUSY) |
| 29 | +esp32_reset = DigitalInOut(board.ESP_RESET) |
| 30 | + |
| 31 | +spi = busio.SPI(board.SCK, board.MOSI, board.MISO) |
| 32 | +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) |
| 33 | +status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) |
| 34 | +wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) |
| 35 | + |
| 36 | +# ------- Sensor Setup ------- # |
| 37 | +# init. the temperature sensor |
| 38 | +i2c_bus = busio.I2C(board.SCL, board.SDA) |
| 39 | +adt = adafruit_adt7410.ADT7410(i2c_bus, address=0x48) |
| 40 | +adt.high_resolution = True |
| 41 | +temperature = "blaa" |
| 42 | +# init. the light sensor |
| 43 | +light_sensor = AnalogIn(board.LIGHT) |
| 44 | + |
| 45 | +# init. the motion sensor |
| 46 | +movement_sensor = DigitalInOut(board.D3) |
| 47 | + |
| 48 | +button1_state = 0 |
| 49 | +button2_state = 0 |
| 50 | + |
| 51 | +# ------------- Screen eliments ------------- # |
| 52 | + |
| 53 | +display = board.DISPLAY |
| 54 | + |
| 55 | +# Backlight function |
| 56 | +def set_backlight(val): |
| 57 | + """Adjust the TFT backlight. |
| 58 | + :param val: The backlight brightness. Use a value between ``0`` and ``1``, where ``0`` is |
| 59 | + off, and ``1`` is 100% brightness. |
| 60 | + """ |
| 61 | + val = max(0, min(1.0, val)) |
| 62 | + board.DISPLAY.auto_brightness = False |
| 63 | + board.DISPLAY.brightness = val |
| 64 | + |
| 65 | +# Touchscreen setup |
| 66 | +ts = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR, |
| 67 | + board.TOUCH_YD, board.TOUCH_YU, |
| 68 | + calibration=((5200, 59000), (5800, 57000)), |
| 69 | + size=(320, 240)) |
| 70 | + |
| 71 | +# ---------- Set the font and preload letters ---------- |
| 72 | +# Be sure to put your font into a folder named "fonts". |
| 73 | +font = bitmap_font.load_font("/fonts/Helvetica-Bold-16.bdf") |
| 74 | +# This will preload the text images. |
| 75 | +font.load_glyphs(b'abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ()') |
| 76 | + |
| 77 | +# ------------- User Inretface Eliments ------------- # |
| 78 | + |
| 79 | +# Make the display context |
| 80 | +splash = displayio.Group(max_size=200) |
| 81 | +board.DISPLAY.show(splash) |
| 82 | + |
| 83 | +# Make a background color fill |
| 84 | +color_bitmap = displayio.Bitmap(320, 240, 1) |
| 85 | +color_palette = displayio.Palette(1) |
| 86 | +color_palette[0] = 0x3D0068 |
| 87 | +bg_sprite = displayio.TileGrid(color_bitmap, x=0, y=0, |
| 88 | + pixel_shader=color_palette) |
| 89 | +splash.append(bg_sprite) |
| 90 | + |
| 91 | +buttons = [] |
| 92 | +# Default button styling: |
| 93 | +BUTTON_WIDTH = 100 |
| 94 | +BUTTON_HEIGHT = 100 |
| 95 | +BUTTON_MARGIN = 10 |
| 96 | + |
| 97 | +# Button Objects |
| 98 | +button_1 = Button(x=BUTTON_MARGIN, y=BUTTON_MARGIN, |
| 99 | + width=BUTTON_WIDTH, height=BUTTON_HEIGHT, |
| 100 | + label="Button 1", label_font=font, |
| 101 | + style=Button.SHADOWROUNDRECT, label_color=0x505050, |
| 102 | + fill_color=0x9e9e9e, outline_color=0x464646) |
| 103 | +buttons.append(button_1) |
| 104 | + |
| 105 | +button_2 = Button(x=BUTTON_MARGIN, y=BUTTON_MARGIN*2+BUTTON_HEIGHT, |
| 106 | + width=BUTTON_WIDTH, height=BUTTON_HEIGHT, |
| 107 | + label="Button 2", label_font=font, |
| 108 | + style=Button.SHADOWROUNDRECT, label_color=0x505050, |
| 109 | + fill_color=0x9e9e9e, outline_color=0x464646) |
| 110 | +buttons.append(button_2) |
| 111 | + |
| 112 | +for b in buttons: |
| 113 | + splash.append(b.group) |
| 114 | + |
| 115 | +# Text Label Objects |
| 116 | +temperature_label = Label(font, text="temperature", color=0xE300D2, max_glyphs=40) |
| 117 | +temperature_label.x = 130 |
| 118 | +temperature_label.y = 20 |
| 119 | +splash.append(temperature_label) |
| 120 | + |
| 121 | +light_label = Label(font, text="lux", color=0xE300D2, max_glyphs=40) |
| 122 | +light_label.x = 130 |
| 123 | +light_label.y = 40 |
| 124 | +splash.append(light_label) |
| 125 | + |
| 126 | +motion_label = Label(font, text="motion", color=0xE300D2, max_glyphs=40) |
| 127 | +motion_label.x = 130 |
| 128 | +motion_label.y = 60 |
| 129 | +splash.append(motion_label) |
| 130 | + |
| 131 | +feed1_label = Label(font, text="MQTT feed1", color=0xE39300, max_glyphs=100) |
| 132 | +feed1_label.x = 130 |
| 133 | +feed1_label.y = 130 |
| 134 | +splash.append(feed1_label) |
| 135 | + |
| 136 | +feed2_label = Label(font, text="MQTT feed2", color=0x00DCE3, max_glyphs=100) |
| 137 | +feed2_label.x = 130 |
| 138 | +feed2_label.y = 200 |
| 139 | +splash.append(feed2_label) |
| 140 | + |
| 141 | +# ------------- MQTT Topic Setup ------------- # |
| 142 | + |
| 143 | +mqtt_topic = 'test/topic' |
| 144 | +mqtt_temperature = 'pyportal/temperature' |
| 145 | +mqtt_lux = 'pyportal/lux' |
| 146 | +mqtt_PIR = 'pyportal/pir' |
| 147 | +mqtt_button1 = 'pyportal/button1' |
| 148 | +mqtt_button2 = 'pyportal/button2' |
| 149 | +mqtt_feed1 = 'pyportal/feed1' |
| 150 | +mqtt_feed2 = 'pyportal/feed2' |
| 151 | + |
| 152 | +# ------------- MQTT Functions ------------- # |
| 153 | + |
| 154 | +# Define callback methods which are called when events occur |
| 155 | +# pylint: disable=unused-argument, redefined-outer-name |
| 156 | +def connect(client, userdata, flags, rc): |
| 157 | + # This function will be called when the client is connected |
| 158 | + # successfully to the broker. |
| 159 | + print('Connected to MQTT Broker!') |
| 160 | + print('Flags: {0}\n RC: {1}'.format(flags, rc)) |
| 161 | + |
| 162 | +def disconnected(client, userdata, rc): |
| 163 | + # This method is called when the client is disconnected |
| 164 | + print('Disconnected from MQTT Broker!') |
| 165 | + |
| 166 | +def subscribe(client, userdata, topic, granted_qos): |
| 167 | + # This method is called when the client subscribes to a new feed. |
| 168 | + print('Subscribed to {0} with QOS level {1}'.format(topic, granted_qos)) |
| 169 | + |
| 170 | +def publish(client, userdata, topic, pid): |
| 171 | + # This method is called when the client publishes data to a feed. |
| 172 | + print('Published to {0} with PID {1}'.format(topic, pid)) |
| 173 | + |
| 174 | +def message(client, topic, message): |
| 175 | + """Method callled when a client's subscribed feed has a new |
| 176 | + value. |
| 177 | + :param str topic: The topic of the feed with a new value. |
| 178 | + :param str message: The new value |
| 179 | + """ |
| 180 | + print('New message on topic {0}: {1}'.format(topic, message)) |
| 181 | + if topic == "pyportal/feed1": |
| 182 | + feed1_label.text = 'Next Bus: {}'.format(message) |
| 183 | + if topic == "pyportal/feed2": |
| 184 | + feed2_label.text = 'Weather: \n {}'.format(message) |
| 185 | + if topic == "pyportal/button1": |
| 186 | + if message == "1": |
| 187 | + buttons[0].label="ON" |
| 188 | + buttons[0].selected = False |
| 189 | + print("Button 1 ON") |
| 190 | + else: |
| 191 | + buttons[0].label="OFF" |
| 192 | + buttons[0].selected = True |
| 193 | + print("Button 1 OFF") |
| 194 | + |
| 195 | +# ------------- Network Connection ------------- # |
| 196 | + |
| 197 | +# Connect to WiFi |
| 198 | +wifi.connect() |
| 199 | + |
| 200 | +# Set up a MiniMQTT Client |
| 201 | +client = MQTT(socket, |
| 202 | + broker = secrets['broker'], |
| 203 | + port = 1883, |
| 204 | + username = secrets['user'], |
| 205 | + password = secrets['pass'], |
| 206 | + network_manager = wifi) |
| 207 | + |
| 208 | +# Connect callback handlers to client |
| 209 | +client.on_connect = connect |
| 210 | +client.on_disconnect = disconnected |
| 211 | +client.on_subscribe = subscribe |
| 212 | +client.on_publish = publish |
| 213 | +client.on_message = message |
| 214 | + |
| 215 | +print('Attempting to connect to %s' % client.broker) |
| 216 | +client.connect() |
| 217 | + |
| 218 | +print('Subscribing to %s, %s, %s, and %s' % (mqtt_feed1, mqtt_feed2, mqtt_button1, mqtt_button2)) |
| 219 | +client.subscribe(mqtt_feed1) |
| 220 | +client.subscribe(mqtt_feed2) |
| 221 | +client.subscribe(mqtt_button1) |
| 222 | +client.subscribe(mqtt_button2) |
| 223 | + |
| 224 | +# ------------- Code Loop ------------- # |
| 225 | +while True: |
| 226 | + # Poll the message queue |
| 227 | + client.loop() |
| 228 | + |
| 229 | + # Read sensor data and format |
| 230 | + light_value = lux = light_sensor.value |
| 231 | + light_label.text = 'Light Sensor: {}'.format(light_value) |
| 232 | + temperature = round(adt.temperature) |
| 233 | + temperature_label.text = 'Temp Sensor: {}'.format(temperature) |
| 234 | + movement_value = movement_sensor.value |
| 235 | + motion_label.text = 'PIR Sensor: {}'.format(movement_value) |
| 236 | + |
| 237 | + # Read display button press |
| 238 | + touch = ts.touch_point |
| 239 | + if touch: |
| 240 | + for i, b in enumerate(buttons): |
| 241 | + if b.contains(touch): |
| 242 | + print('Sending button%d pressed' % i) |
| 243 | + if i == 0: |
| 244 | + # Toggle switch button type |
| 245 | + if button1_state == 0: |
| 246 | + button1_state = 1 |
| 247 | + b.label = "ON" |
| 248 | + b.selected = False |
| 249 | + print("Button 1 ON") |
| 250 | + else: |
| 251 | + button1_state = 0 |
| 252 | + b.label = "OFF" |
| 253 | + b.selected = True |
| 254 | + print("Button 1 OFF") |
| 255 | + print('Sending button 1 state: ') |
| 256 | + client.publish(mqtt_button1, button1_state) |
| 257 | + # for debounce |
| 258 | + while ts.touch_point: |
| 259 | + print("Button 1 Pressed") |
| 260 | + if i == 1: |
| 261 | + # Momentary button type |
| 262 | + b.selected = True |
| 263 | + print('Sending button 2 state: ') |
| 264 | + client.publish(mqtt_button2, 1) |
| 265 | + # for debounce |
| 266 | + while ts.touch_point: |
| 267 | + print("Button 2 Pressed") |
| 268 | + print("Button 2 reliced") |
| 269 | + print('Sending button 2 state: ') |
| 270 | + client.publish(mqtt_button2, 0) |
| 271 | + b.selected = False |
| 272 | + |
| 273 | + # Publish sensor data to MQTT |
| 274 | + print('Sending light sensor value: %d' % light_value) |
| 275 | + client.publish(mqtt_lux, light_value) |
| 276 | + |
| 277 | + print('Sending temperature value: %d' % temperature) |
| 278 | + client.publish(mqtt_temperature, temperature) |
| 279 | + |
| 280 | + print('Sending motion sensor value: %d' % movement_value) |
| 281 | + client.publish(mqtt_PIR, '{}'.format(movement_value)) |
0 commit comments