Part 2: Fabrication and Assembly

With Noah Saxenian, ideated and created a lighthouse themed nightlight with multiple functionalities

Project Goals

Project Documentation

https://www.youtube.com/watch?v=vehepYOVP_Q

This video displays the nightlight in action. The nightlight can be turned on and off using the respective buttons on the UI. The UI also displays the most recent messages to the lighthouse, as well as the connection status to the MQTT broker. When tapped, the lighthouse frosted window will change colors. When the name poster is pressed, the lighthouse servo and light turn on until pressed again.

https://youtu.be/OiVF81LJLH0

This video showcases the cross-sync functionality we attempted with a second group’s nightlight. When sync is enabled in on the user UI, tapping the lighthouse now not only changes the frosted window light, but also sends an MQTT command to the other group for interpretation. Similarly, when sync is turned on and the other group taps their nightlight, the LED within the lighthouse stops and blinks 5 times.

Successes and Challenges

Codespace

def __init__(self):
              
    # on/off flag
    self.on = True
    self.button_toggle = False
    self.collab = False
    self.sync = False
    
    # connect
    self.connect_wifi(2)
    self.start_mqtt()
    
    # setup acccelerometer
    scl = Pin('GPIO27', Pin.OUT)
    sda = Pin('GPIO26', Pin.OUT)
    self.accel = Acceleration(scl, sda)
    self.accel.enable_tap_interrupt()
    
    # interrupt from accelerometer
    self.int = Pin(10, Pin.IN)
    self.int.irq(trigger=Pin.IRQ_FALLING, handler=self.on_tap)
    
    self.button = Pin(9, Pin.IN, Pin.PULL_UP)
    self.button.irq(trigger=Pin.IRQ_FALLING, handler=self.button_press)

    # setup LED
    self.led = Pin(6, Pin.OUT)
    self.led.off()
    
    # setup servo
    self.servo = PWM(Pin(22))
    self.servo.freq(50)
    
    # setup neopixel
    self.neo = neopixel.NeoPixel(Pin(28),1)
    self.neo[0] = (0,0,0)
    self.neo.write()
    
    # startup asyncio
    asyncio.create_task(self.check_messages())
    asyncio.create_task(self.pan_servo())
    asyncio.get_event_loop().run_forever()

This is the initializing of the nightlight class. Here, all the pins were called out, including setting up the I2C bus for the accelerometer. The class has a couple key features at the top which are self.on, self.button_toggle, self.collab, and self.sync. The first two are parameters are variables that are checked down the line to enable certain functionality, while the other two are used to check for cross-sync functionality with the other group’s nightlight.

def connect_wifi(self, index=2):
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect("Tufts_Robot", "")
    #wlan.connect(mysecrets[index]['SSID'], mysecrets[index]['key'])
    while wlan.ifconfig()[0] == '0.0.0.0':
        print('.', end=' ')
        time.sleep(1)
    print('wifi connected')
    return wlan.ifconfig()

def start_mqtt(self):
    # connect MQTT client and subscribe to topic
    mqtt_broker = 'broker.hivemq.com' 
    port = 1883
	  topic_sub = 'ME35-24/Kaisnightlight'
	
	def callback(topic, msg):
	    print('Received: Topic: %s, Message: %s' % (topic, msg))
	    # callback checks if topic and message are correct to turn on/off
	    if topic.decode() == topic_sub:
	        if msg.decode() == 'on':
	            self.on = True
	            print('on')
	        if msg.decode() == 'off':
	            self.on = False
	            self.update_neopixel()
	            print('off')
	        if msg.decode() == 'blink':
	            print("Read from collab")
	            self.collab = True
	            if self.on == True:
	                self.blinkLED()
	            else:
	                self.collab = False 
	        if msg.decode() == 'sync on':
	            self.sync = True
	        if msg.decode() == 'sync off':
	            self.sync = False
	
	self.client = MQTTClient('Noah', mqtt_broker , port, keepalive=0)
	self.client.connect()
	print('Connected to %s MQTT broker' % (mqtt_broker))
	self.client.set_callback(callback)          # set the callback if anything is read
	self.client.subscribe(topic_sub.encode())   # subscribe to a bunch of topics
    
async def check_messages(self):
    # constantly check for new MQTT messages
    while True:
        self.client.check_msg()
        await asyncio.sleep(0.5)