# Embedded UE3 # 1. Actuators ## a) Then investigate the script blink.py and run it. Describe its behavior and add a picture of your setup ```python import RPi.GPIO as GPIO from time import sleep import logging # setup logging logger = logging.getLogger(__name__) logging.basicConfig(level="INFO") # set GPIO Mode GPIO.setmode(GPIO.BCM) # setup GPIO pins GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(24, GPIO.OUT) GPIO.setup(25, GPIO.OUT) GPIO.output(24, False) GPIO.output(25, False) pin=24 try: while True: button_state = GPIO.input(18) logger.info("button state is %s (pressed=%s)",button_state,not bool(button_state)) if button_state == False: pin=24 else: pin=25 GPIO.output(pin, True) sleep(1) GPIO.output(pin, False) sleep(1) except KeyboardInterrupt: logger.info("cleaning up ...") GPIO.cleanup() ``` **Setup:** ![](https://hackmd.io/_uploads/Hk8uFnvE3.png) **Describe its behavior:** - On button press, state will be toggled (which is read from GPIO input pin 18). When the button is not pressed, the red LED (pin 24) will blink. When the button is pressed, the green LED (pin 25) will blink. **Testen**: Pin auf 5V pin setzen. Siehe reference Reference: https://de.pinout.xyz/pinout/pin2_5v_stromversorgung# ## b) Investigate the script blink threaded.py and run it. Describe the differences to the previous script: ```python import RPi.GPIO as GPIO import time GPIO.setmode(GPIO.BCM) import threading import logging # setup logging logger = logging.getLogger(__name__) logging.basicConfig(level="INFO") led_pin=24 class Button(): def __init__(self, channel): self.channel = channel self._thread=threading.Thread(name='button',target=self.run) self._thread.deamon = True self._thread_active = True self._thread.start() def run(self): logger.info("button thread started") previous = 1 current = 0 while self._thread_active: time.sleep(0.01) current = GPIO.input(self.channel) logger.debug("current %s previous %s",current,previous) if current==1 and previous==0: logger.info("button was pressed and released") self.onButtonPress() previous = current def onButtonPress(self): global led_pin if led_pin==24: led_pin=25 else: led_pin=24 GPIO.output(24, False) GPIO.output(25, False) def stop(self): logger.debug("stopping thread") self._thread_active = False try: # setup gpio GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP) button=Button(18) GPIO.setup(24, GPIO.OUT) GPIO.setup(25, GPIO.OUT) GPIO.output(24, False) GPIO.output(25, False) while True: # toggle gpio GPIO.output(led_pin, True) time.sleep(1) GPIO.output(led_pin, False) time.sleep(1) except KeyboardInterrupt: button.stop() logger.info("stopping ...") time.sleep(1) GPIO.cleanup() ``` **Differences:** - Toggling instead of holding. - Toggling after fallen edge - Button press is detected faster (because it's only sleeping for 0.01s instead of 1s) nonblocking # 2. Connectivity ## a) **Change the matriculation number:** ```python def on_connect(client, userdata, flags, rc): logger.info('Connected with result code %s',str(rc)) client.subscribe("12024183", qos=0) ``` Complete the source code of remotecontrol.py so that it correctly switches on and off the lights, based on received messages ```python #!/usr/bin/python from __future__ import division import time import paho.mqtt.client as mqtt import logging import RPi.GPIO as GPIO from at.jku.pervasive.eps.mymqttmessages.mymqttmessages_pb2 import * # setup logging logger = logging.getLogger(__name__) logging.basicConfig(level="INFO") # setup gpio GPIO.setmode(GPIO.BCM) LED_RED=25 LED_GREEN=24 GPIO.setup(LED_RED, GPIO.OUT) GPIO.setup(LED_GREEN, GPIO.OUT) GPIO.output(LED_RED, False) GPIO.output(LED_GREEN, False) # mqtt connect callback function def on_connect(client, userdata, flags, rc): logger.info('Connected with result code %s',str(rc)) # Subscribing in on_connect() means that if we lose the connection and # reconnect then subscriptions will be renewed. client.subscribe("12024183", qos=0) # mqtt message received callback function def on_message(client, userdata, msg): commandString=str(msg.payload) proto_msg = PBMessage() try: proto_msg.ParseFromString(msg.payload) if proto_msg.HasField('ledControl'): logger.debug('got message at %s with content %s',str(msg.topic),commandString) logger.info('got message from %s (with target %s)',proto_msg.source,proto_msg.target) logger.info('ledControl numberic %s %s %s',proto_msg.ledControl.action,proto_msg.ledControl.led,proto_msg.ledControl.toggleRateHz) logger.info('ledControl Info %s %s %s',LedAction.Name(proto_msg.ledControl.action),Led.Name(proto_msg.ledControl.led),proto_msg.ledControl.toggleRateHz) led_pin=-1 # Set pin if Led.Value('RED')==proto_msg.ledControl.led: led_pin=LED_RED elif Led.Value('GREEN')==proto_msg.ledControl.led: led_pin=LED_GREEN else: logger.error('cannot map led %s to pin',Led.Name(proto_msg.ledControl.led)) return # Set action # TODO: Read action from message and control LED if proto_msg.ledControl.action == LedAction.Value("OFF"): GPIO.output(led_pin, 0) #turn off elif proto_msg.ledControl.action == LedAction.Value("ON"): GPIO.output(led_pin, 1) #turn on elif proto_msg.ledControl.action == LedAction.Value("TOGGLE"): current = GPIO.input(led_pin) GPIO.output(led_pin, not current) else: GPIO.output(led_pin,0) # end of ledControl processing else: logger.warn('got message at %s with content %s',str(msg.topic),commandString) except: logger.warning('Unable to decode message: No valid ProtoBuf Msg received') # setup mqtt client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message # connect mqtt client.connect("iot.soft.uni-linz.ac.at", 1883, 60) try: client.loop_forever() except (KeyboardInterrupt, SystemExit): logger.info('disconnecting ...') client.disconnect() time.sleep(1) GPIO.cleanup() ``` TODO: - Execute and collect ## b) ```java public class ProtobufMqttProgram { // embeddedsystems2019 private static final String DEFAULT_TOPIC = "12024183"; public static void main(String[] args) { ProtobufMqttProgram connector = new ProtobufMqttProgram(); try { Thread.sleep(2000); // unsubscribe to not consume sent messages // connector.sampleClient.unsubscribe(DEFAULT_TOPIC); // qos = 2 (exactly once) // TODO: Publish different LedControl Messages connector.sendLedControl(Led.RED, LedAction.ON, 0); Thread.sleep(5000); // Publish LedControl with color=red, action=off, togglerate=0 connector.sendLedControl(Led.RED, LedAction.OFF, 0); Thread.sleep(5000); // Publish LedControl with color=green, action=on, togglerate=0 connector.sendLedControl(Led.GREEN, LedAction.ON, 0); Thread.sleep(5000); // Publish LedControl with color=green, action=off, togglerate=0 connector.sendLedControl(Led.GREEN, LedAction.OFF, 0); Thread.sleep(5000); connector.close(); } catch (MqttException e) { processEx(e); } catch (InterruptedException e) { e.printStackTrace(); } } } ``` ``` ``` Logs: ``` INFO:__main__:Connected with result code 0 INFO:__main__:got message from 3576804469 (with target 0) INFO:__main__:ledControl numberic 1 0 0 INFO:__main__:ledControl Info ON RED 0 INFO:__main__:got message from 3576804469 (with target 0) INFO:__main__:ledControl numberic 0 0 0 INFO:__main__:ledControl Info OFF RED 0 INFO:__main__:got message from 3576804469 (with target 0) INFO:__main__:ledControl numberic 1 1 0 INFO:__main__:ledControl Info ON GREEN 0 INFO:__main__:got message from 3576804469 (with target 0) INFO:__main__:ledControl numberic 0 1 0 INFO:__main__:ledControl Info OFF GREEN 0 ``` # 3. Message Format ## a) Protobuf messages: ``` connector.sendLedControl(Led.RED, LedAction.ON, 0); connector.sendLedControl(Led.RED, LedAction.OFF, 0); connector.sendLedControl(Led.GREEN, LedAction.ON, 0); connector.sendLedControl(Led.GREEN, LedAction.OFF, 0); ``` Output Protobuf ``` INFO a.j.p.eps.ProtobufMqttProgram - Connecting to broker: tcp://iot.soft.uni-linz.ac.at:1883 INFO a.j.p.eps.ProtobufMqttProgram - connected to tcp://iot.soft.uni-linz.ac.at:1883 INFO a.j.p.eps.ProtobufMqttProgram - message size 11 WARN a.j.p.eps.ProtobufMqttProgram - got led control from 997924158 with target 0 INFO a.j.p.eps.ProtobufMqttProgram - message size 9 WARN a.j.p.eps.ProtobufMqttProgram - got led control from 997924158 with target 0 INFO a.j.p.eps.ProtobufMqttProgram - message size 13 WARN a.j.p.eps.ProtobufMqttProgram - got led control from 997924158 with target 0 INFO a.j.p.eps.ProtobufMqttProgram - message size 11 WARN a.j.p.eps.ProtobufMqttProgram - got led control from 997924158 with target 0 ``` JSON Messages: ``` {"LED":"RED","ACTION":"TOGGLE","TOGGLERATE":"5"} {\"LED\":\"GREEN\",\"ACTION\":\"ON\",\"TOGGLERATE\":\"0\"} {\"LED\":\"BLUE\",\"ACTION\":\"OFF\",\"TOGGLERATE\":\"0\"} {\"LED\":\"GREEN\",\"ACTION\":\"ON\",\"TOGGLERATE\":\"0\"} {\"LED\":\"RED\",\"ACTION\":\"OFF\",\"TOGGLERATE\":\"0\"} {\"LED\":\"BLUE\",\"ACTION\":\"TOGGLE\",\"TOGGLERATE\":\"1\"} ``` Output JSON ``` INFO at.jku.pervasive.eps.TextMqttProgram - Connecting to broker: tcp://iot.soft.uni-linz.ac.at:1883 INFO at.jku.pervasive.eps.TextMqttProgram - connected to tcp://iot.soft.uni-linz.ac.at:1883 INFO at.jku.pervasive.eps.TextMqttProgram - message size 48 INFO at.jku.pervasive.eps.TextMqttProgram - message size 46 INFO at.jku.pervasive.eps.TextMqttProgram - message size 46 INFO at.jku.pervasive.eps.TextMqttProgram - message size 46 INFO at.jku.pervasive.eps.TextMqttProgram - message size 45 INFO at.jku.pervasive.eps.TextMqttProgram - message size 49 ``` ## b) ### Protobuf Uses binary encoding - Enums (like LedAction) can be represented with minimal bit amount ``` Led.RED, LedAction.ON, 0 ``` ### JSON Uses ASCII encoding - Instead of representing actions as an enum, they are represented as strings. So we need 6 bytes instead of 2 bits (which is rounded up to 1 byte). - There's also lots of useless information needed to structure the message (':' and '{}') ``` "{\"LED\":\"RED\",\"ACTION\":\"TOGGLE\",\"TOGGLERATE\":\"5\"}" ```