# Get Into IoT Activity Sheets [TOC] # Setup ## Prerequisites For this session you will need: * A laptop or PC * Raspberry Pi Zero (provided) * IoT LoRa Node pHAT (provided) * Sensors and Breadboard (provided) ## Procedure 1. Connect your PC or laptop to the `DMC-Tenant1` WiFi network using the password `DMC2-PsK2020`. 2. Download and install [Thonny Python IDE](https://thonny.org/) (free software). 3. Configure Thonny to connect to your Raspberry Pi Zero by going to `Tools-->Options` ![](https://i.imgur.com/OQSbQCA.png)<br/><br/> 4. Select the Interpreter tab and from the dropdown choose `Remote Python 3 (SSH)` ![](https://i.imgur.com/HP6aJno.png)<br/><br/> 5. In the Host field, enter the IP address for your Raspberry Pi Zero as provided by the session facilitator. Enter `pi` in the Username field and click OK. ![](https://i.imgur.com/dyjOtR3.png)<br/><br/> 6. In the prompt that appears, enter the password `raspberry`, check remember password then click OK. ![](https://i.imgur.com/EOAXd49.png)<br/><br/> 7. Wait for the Raspberry Pi Zero to connect. When it does, the Thonny window should look something like the following: ![](https://i.imgur.com/NcaSVi3.png)<br/><br/> 8. In the directory listing for the Rasperry Pi Zero, double click the `hello_world.py` script and press the green run button in the Thonny menu bar. If all went well, you should see the following output in the Shell: ``` >>> %Run hello_world.py Hello, world! >>> ``` # Introduction ## Raspberry Pi Zero W ![](https://www.distrelec.biz/Web/WebShopImages/landscape_large/5-/01/Raspberry_Pi_Zero_W_30113445-01.jpg) Our embedded system is a [Raspberry Pi Zero W](https://www.raspberrypi.com/products/raspberry-pi-zero-w/) single board computer. It runs a version of Linux called Raspbian from an included SD card and has interfaces for WiFi, Bluetooth, HDMI, USB, a camera, and several general purpose inputs and outputs (GPIO). To power the board, plug the provided USB cable into an USB port on your PC or laptop or a micro USB phone charger. ## IoT Lora Node pHAT Here is an overview of the IoT LoRa Node pHAT for reference when connecting up your sensor(s). ![](https://i.imgur.com/35qWJrA.png) |Pin|Description| |--|--| |5V|Provides 5 volt power output| |3V3|Provides 3.3 volt power output| |GND|Provides ground for either 3.3V or 5V power| |GPIO2|I2C data pin by default, can be reconfigured |GPIO3|I2C clock pin by default, can be reconfigured |GPIO4|1-wire serial pin or general purpose digital I/O| # Sensors ## Smart Temperature & Humidity Sensor ### Sensor Overview The [DHT11](https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf) is a low cost Temperature and Humidity sensor which is commonly used in IoT projects. The breakout module has three pins: power, ground, and Signal. The sensor uses a single wire serial protocol known as 1-wire. ![](https://i.imgur.com/KbRtDLh.png) ### Hardware Setup Attach the sensor to the pHAT using the jumper wires provided using the following connections: |Sensor Pin| pHAT Pin| |--|--| |Signal| GPIO4| |Vcc (+)| 3V3| |Ground (-) | GND| ### Python Code You can test that the sensor is connected correctly by running the `dht11_test.py` script from Thonny. ```python= from rak811.rak811 import Mode, Rak811 #Lora Chip driver import RPi.GPIO as GPIO # RPi GPIO library import dht11 # Sensor library from time import sleep # Timing library from cayennelpp import LppFrame # LoRaWAN payload library # Initialize GPIO GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.cleanup() # Read DHT11 data using pin 4 sensor = dht11.DHT11(pin = 4) # Initialize RAK811 LoRa module lora = Rak811() lora.hard_reset() lora.mode = Mode.LoRaWan lora.band = 'EU868' # Configure TTN credentials lora.set_config(app_eui='0101010101010101', app_key='' ) # Join TTN LoRaWAN lora.join_otaa() lora.dr = 5 # Read and publish sensor data forever while True: # Read from sensor result = sensor.read() # If results are valid, publish readings to TTN if result.is_valid(): print("Temperature: %-3.1f C" % result.temperature) print("Humidity: %-3.1f %%" % result.humidity) # Create a Cayenne data frame frame = LppFrame() # Add readings to data frame frame.add_temperature(0, result.temperature) frame.add_humidity(0, result.humidity) # Publish data frame to TTN print("Publishing to TTN") lora.send(bytes(frame)) # Sleep for 5 seconds to adhere to LoRaWAN duty cycle limits sleep(5) lora.close() ``` ## Sound Threshold Detector ### Sensor Overview This module uses an electret microphone in conjuction with an amplifer. It has two outputs: * AO: analog output, real-time output voltage signal of the microphone * DO: when the intensity of the sound reaches a certain threshold, the output is a high or low level signal. The threshold sensitivity can be achieved by adjusting the potentiometer. :::info The sound threshold level will need to be set manually using the screw on the sensor. Turn the screw on the blue potentiometer until the LED is off but flashes for loud sounds. Anticlockwise is less sensitive and it can take several turns before you see a response. ::: ![](https://i.imgur.com/UqPMv2T.png) ### Hardware Setup Because the Raspberry Pi cannot directly read analog voltages, we are constrained to use on the digital output from this sensor. Attach the sensor to the pHAT using the jumper wires provided using the following connections: |Sensor Pin| pHAT Pin| |--|--| |DO (1)| GPIO4| |VCC (2)| 3V3| |GND (3) | GND| ### Python Code ```python= from rak811.rak811 import Mode, Rak811 # LoRa chip driver import RPi.GPIO as GPIO # RPi GPIO library from time import sleep # Time delay library from cayennelpp import LppFrame # LoRa payload library # Define a flag to indicate whether the sound threshold was exceeded or not alert = False # Callback function to set this flag when sound level is exceeded def threshold_cb(channel): global alert alert = True # initialize GPIO GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) # Set up pin 2 as input and attached interrupt on rising edge GPIO.setup(2, GPIO.IN) GPIO.add_event_detect(2, GPIO.RISING, callback=threshold_cb, bouncetime=100) # Initialize RAK811 LoRa module lora = Rak811() lora.hard_reset() lora.mode = Mode.LoRaWan lora.band = 'EU868' # Configure TTN credentials lora.set_config(app_eui='0101010101010101', app_key='' ) # Join TTN LoRaWAN lora.join_otaa() lora.dr = 5 # Read and publish sensor data forever while True: # Create a Cayenne data frame frame = LppFrame() frame.add_digital_input(0, alert) # Publish data frame to TTN print("Publishing to TTN") lora.send(bytes(frame)) # Reset alert flag alert = False # Sleep for 5 seconds to adhere to LoRaWAN duty cycle limits sleep(5) lora.close() ``` ## Light Level Sensor ### Sensor Overview An LDR (sometimes called a photocell) is a special type of resistor. When light hits the LDR, its resistance is very low, but when it’s in the dark its resistance is very high. By placing a capacitor in series with an LDR, the capacitor will charge at different speeds depending on whether it’s light or dark. When the capacitor is charged, it will activate a digital input on the Raspberry Pi. By measuring the time it takes to charge the capacitor, we can estimate the resistance of the LDR and hence the incident light level. ### Hardware Setup Setup the LDR and capacitor as shown below. :::danger Ensure the white stripe on the capacitor is orientated as shown otherwise it will be damaged! ::: ![](https://projects-static.raspberrypi.org/projects/physical-computing/765b944f3fe3d57bd3568794ff6527f72b57ddc8/en/images/Laser-tripwire_3-01.jpg) Attach the sensor to the pHAT using the jumper wires provided using the following connections: |Sensor Pin| pHAT Pin| |--|--| |LDR (red)| 3V3| |Midpoint (blue)| GPIO4| |Capacitor tail (black) | GND| ### Python Code ```python= from rak811.rak811 import Mode, Rak811 # LoRa chip driver import RPi.GPIO as GPIO # RPi GPIO library import time # timing library from cayennelpp import LppFrame # LoRa payload library from gpiozero import LightSensor # Light sensor library import math # maths function library (for statistics) # initialize GPIO GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) # Initialize light sensor on GPIO pin 4 ldr = LightSensor(4) # Read LDR sensor over given time period and calculate # sensor statistics def sample_ldr(sample_duration=1): t_start = time.time() samples = [] while time.time() < t_start + sample_duration: samples.append(ldr.value*10000) stats = {} n = len(samples) mean = sum(samples) / n std = math.sqrt(sum((s-mean)**2 for s in samples) / n) return { "min": min(samples), "max": max(samples), "mean": mean, "std": std } # Initialize RAK811 LoRa module lora = Rak811() lora.hard_reset() lora.mode = Mode.LoRaWan lora.band = 'EU868' # Configure TTN credentials lora.set_config(app_eui='0101010101010101', app_key='' ) # Join TTN LoRaWAN lora.join_otaa() lora.dr = 5 # Read and publish sensor data forever while True: # Create a Cayenne data frame frame = LppFrame() # Sample light level for 10 seconds light_stats = sample_ldr(10) # Publish sensor stats frame.add_luminosity(0, light_stats['min']) frame.add_luminosity(1, light_stats['max']) frame.add_luminosity(2, light_stats['mean']) frame.add_luminosity(3, light_stats['std']) # Publish data frame to TTN print("Publishing to TTN") lora.send(bytes(frame)) lora.close() ``` ## Ultrasonic Range Sensor ### Sensor Overview ![](https://projects-static.raspberrypi.org/projects/physical-computing/765b944f3fe3d57bd3568794ff6527f72b57ddc8/en/images/ultrasonic-distance-sensor.png) In air, sound travels at a speed of 343 metres per second. An ultrasonic distance sensor sends out pulses of ultrasound which are inaudible to humans, and detects the echo that is sent back when the sound bounces off a nearby object. It then uses the speed of sound to calculate the distance from the object. ### Hardware Setup :::info Due to the potential for damage to the Raspberry Pi, the breadboard has been pre-populated for you. ::: This sensor needs a 5V power supply so your Raspberry Pi Lora Node pHAT has been modified to provide an additional power pin for this purpose (see [here](#IoT-Lora-Node-pHAT) for reference). This means that the output voltage from this sensor is too high for the inputs on the Raspberry Pi, so to prevent damage the voltage is stepped down by the two resistors on the breadboard. Attach the sensor to the pHAT using the jumper wires provided using the following connections: |Sensor Pin| pHAT Pin| |--|--| |Power (red)| 5V| |Trigger (green)| GPIO2| |Echo (yellow) | GPIO4 | |Ground (black) | GND| ### Python Code ```python= from rak811.rak811 import Mode, Rak811 # LoRa chip driver from gpiozero.pins.pigpio import PiGPIOFactory # RPi GPIO pin driver from gpiozero import DistanceSensor # Sensor library import time # Timing library from cayennelpp import LppFrame # LoRa payload library import math # Math functions library (for statistics) # Instantiate sensor factory = PiGPIOFactory() ultrasonic = DistanceSensor(echo=4, trigger=2, max_distance=4, pin_factory=factory) # Take readings from sensor over a given period and summarise with descriptive statistics def sample(sample_duration=1): t_start = time.time() samples = [] while time.time() < t_start + sample_duration: samples.append(ultrasonic.distance) stats = {} n = len(samples) mean = sum(samples) / n std = math.sqrt(sum((s-mean)**2 for s in samples) / n) return { "min": min(samples), "max": max(samples), "mean": mean, "std": std } # Initialize RAK811 LoRa module lora = Rak811() lora.hard_reset() lora.mode = Mode.LoRaWan lora.band = 'EU868' # Configure TTN credentials lora.set_config(app_eui='0101010101010101', app_key='' ) # Join TTN LoRaWAN print("Joining LoRaWAN...") lora.join_otaa() lora.dr = 5 # Read and publish sensor data forever while True: # Create a Cayenne data frame frame = LppFrame() range_stats = sample(10) frame.add_analog_input(0, range_stats['min']) frame.add_analog_input(1, range_stats['max']) frame.add_analog_input(2, range_stats['mean']) frame.add_analog_input(3, range_stats['std']) print(frame) # Publish data frame to TTN print("Publishing to TTN") lora.send(bytes(frame)) lora.close() ``` ## PIR Motion Sensor ## Sensor Overview Humans and other animals emit radiation all the time. This is nothing to be concerned about, though, as the type of radiation we emit is infrared radiation (IR), which is pretty harmless at the levels at which it is emitted by humans. In fact, all objects at temperatures above absolute zero (-273.15C) emit infrared radiation. A PIR sensor detects changes in the amount of infrared radiation it receives. When there is a significant change in the amount of infrared radiation it detects, then a pulse is triggered. This means that a PIR sensor can detect when a human (or any animal) moves in front of it. ## Hardware Setup ![](https://i.imgur.com/zRphfM9.png) This sensor requires 5V power instead of 3.3V, so your Raspberry Pi LoRa Node pHAT has been modified to provide an additional 5V pin. See [here](#IoT-Lora-Node-pHAT) for reference. Attach the sensor to the pHAT using the jumper wires provided using the following connections: |Sensor Pin| pHAT Pin| |--|--| |Output| GPIO4| |Power| 5V | |Ground | GND| ## Python Code ```python= from rak811.rak811 import Mode, Rak811 # LoRa chip driver from gpiozero import MotionSensor # Sensor library import time # Timing library from cayennelpp import LppFrame # LoRa payload library # Variables to keep track of when we last transmitted, and how often we want to transmit last_transmit_time = time.time() transmit_interval = 5 # seconds # Instantiate the motion sensor pir = MotionSensor(4) # Initialize RAK811 LoRa module lora = Rak811() lora.hard_reset() lora.mode = Mode.LoRaWan lora.band = 'EU868' # Configure TTN credentials lora.set_config(app_eui='0101010101010101', app_key='' ) # Join TTN LoRaWAN print("Joining LoRaWAN...") lora.join_otaa() lora.dr = 5 # Read and publish sensor data forever while True: motion = False # Create a Cayenne data frame frame = LppFrame() pir.wait_for_motion(5) if pir.motion_detected: motion = True frame.add_presence(0,motion) # Publish data frame to TTN print("Publishing to TTN") lora.send(bytes(frame)) time.sleep(max(0, transmit_interval - (time.time() - last_transmit_time))) last_transmit_time = time.time() lora.close() ``` # Device Allocations |LoRa Device EUI| RPi MAC Address|IP Address| Role| |--|--|--|--| |60C5A8FFFE78++B303++|B8:27:EB:85:0C:7C|172.17.111.217|PIR Motion Sensor| |60C5A8FFFE78++B2D0++|B8:27:EB:C6:AF:A8|172.17.111.240|Light Level Sensor| |60C5A8FFFE78++B223++|B8:27:EB:0D:34:F1|172.17.111.238|Ultrasonic Distance Sensor| |60C5A8FFFE78++B345++|B8:27:EB:62:EE:ED|172.17.111.239|Temperature and Humidity Sensor| |60C5A8FFFE78++B22E++|B8:27:EB:3E:48:2A|172.17.111.241|Sound Threshold Detector| <!-- :::warning 60C5A8FFFE78++B2C5++ is possibly damaged ::: --> # Node Red Example ```javascript= [ { "id": "0379d6b85cd091e6", "type": "tab", "label": "Flow 1", "disabled": false, "info": "", "env": [] }, { "id": "338ce01dc6cd3d45", "type": "mqtt in", "z": "0379d6b85cd091e6", "name": "", "topic": "#", "qos": "2", "datatype": "json", "broker": "b0479d9283a99332", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 70, "y": 180, "wires": [ [ "a33fef212b79cdfb", "a8642d722d010b7d" ] ] }, { "id": "a33fef212b79cdfb", "type": "debug", "z": "0379d6b85cd091e6", "name": "", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 250, "y": 60, "wires": [] }, { "id": "a8642d722d010b7d", "type": "switch", "z": "0379d6b85cd091e6", "name": "", "property": "topic", "propertyType": "msg", "rules": [ { "t": "eq", "v": "v3/dmc02-makerlab@rjc-home/devices/dmc-lora-phat-60c5a8fffe78b223/up", "vt": "str" }, { "t": "eq", "v": "v3/dmc02-makerlab@rjc-home/devices/dmc-lora-phat-60c5a8fffe78b22e/up", "vt": "str" }, { "t": "eq", "v": "v3/dmc02-makerlab@rjc-home/devices/dmc-lora-phat-60c5a8fffe78b2d0/up", "vt": "str" }, { "t": "eq", "v": "v3/dmc02-makerlab@rjc-home/devices/dmc-lora-phat-60c5a8fffe78b303/up", "vt": "str" }, { "t": "eq", "v": "v3/dmc02-makerlab@rjc-home/devices/dmc-lora-phat-60c5a8fffe78b345/up", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 5, "x": 230, "y": 180, "wires": [ [ "56f29c40d810e578" ], [ "2bebbd1a3b9c4cf2" ], [ "6c8ca1c4058f047f" ], [ "99d88abdad548205" ], [ "d30888b9bcbd593c" ] ] }, { "id": "b9e1933908a6e7a2", "type": "link out", "z": "0379d6b85cd091e6", "name": "ultrasonic-distance-sensor", "mode": "link", "links": [ "938f62da889d1c32" ], "x": 515, "y": 100, "wires": [] }, { "id": "0ccfd39fce55e47b", "type": "link out", "z": "0379d6b85cd091e6", "name": "sound-threshold-detector", "mode": "link", "links": [ "938f62da889d1c32" ], "x": 515, "y": 140, "wires": [] }, { "id": "4806fc7172f307b1", "type": "link out", "z": "0379d6b85cd091e6", "name": "light-level-sensor", "mode": "link", "links": [ "938f62da889d1c32" ], "x": 515, "y": 180, "wires": [] }, { "id": "998fb78920616d2f", "type": "link out", "z": "0379d6b85cd091e6", "name": "pir-motion-sensor", "mode": "link", "links": [ "938f62da889d1c32" ], "x": 515, "y": 220, "wires": [] }, { "id": "644f4c8b8ccabc60", "type": "link out", "z": "0379d6b85cd091e6", "name": "temp-humid-sensor", "mode": "link", "links": [ "938f62da889d1c32", "1918a9db9abfcb72" ], "x": 515, "y": 260, "wires": [] }, { "id": "59a54f228cf5f17c", "type": "comment", "z": "0379d6b85cd091e6", "name": "ultrasonic-distance-sensor", "info": "", "x": 650, "y": 100, "wires": [] }, { "id": "19afda2ec546e2b0", "type": "comment", "z": "0379d6b85cd091e6", "name": "sound-threshold-detector", "info": "", "x": 650, "y": 140, "wires": [] }, { "id": "f69ea66a6e0ab03f", "type": "comment", "z": "0379d6b85cd091e6", "name": "light-level-sensor", "info": "", "x": 620, "y": 180, "wires": [] }, { "id": "7f4f93583105eae2", "type": "comment", "z": "0379d6b85cd091e6", "name": "pir-motion-sensor", "info": "", "x": 620, "y": 220, "wires": [] }, { "id": "6341ba603ff6c1fa", "type": "comment", "z": "0379d6b85cd091e6", "name": "temp-humid-sensor", "info": "", "x": 630, "y": 260, "wires": [] }, { "id": "d30888b9bcbd593c", "type": "function", "z": "0379d6b85cd091e6", "name": "", "func": "msg.topic = \"temp-humid-sensor\";\nconst data = msg.payload.uplink_message.decoded_payload;\nmsg.payload = {\n humidity: data.relative_humidity_0,\n temperature: data.temperature_0\n};\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 420, "y": 260, "wires": [ [ "644f4c8b8ccabc60" ] ] }, { "id": "99d88abdad548205", "type": "function", "z": "0379d6b85cd091e6", "name": "", "func": "msg.topic = \"pir-motion-sensor\";\nmsg.payload = msg.payload.uplink_message.decoded_payload.presence_0;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 420, "y": 220, "wires": [ [ "998fb78920616d2f" ] ] }, { "id": "6c8ca1c4058f047f", "type": "function", "z": "0379d6b85cd091e6", "name": "", "func": "msg.topic = \"light-level-sensor\";\nconst data = msg.payload.uplink_message.decoded_payload;\nmsg.payload = {\n min: data.luminosity_0,\n max: data.luminosity_1,\n mean: data.luminosity_2,\n std: data.luminosity_3\n}\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 420, "y": 180, "wires": [ [ "4806fc7172f307b1" ] ] }, { "id": "2bebbd1a3b9c4cf2", "type": "function", "z": "0379d6b85cd091e6", "name": "", "func": "msg.topic = \"sound-threshold-detector\";\nmsg.payload = msg.payload.uplink_message.decoded_payload.digital_in_0;\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 420, "y": 140, "wires": [ [ "0ccfd39fce55e47b" ] ] }, { "id": "56f29c40d810e578", "type": "function", "z": "0379d6b85cd091e6", "name": "", "func": "msg.topic = \"ultrasonic-distance-sensor\";\nconst data = msg.payload.uplink_message.decoded_payload;\nmsg.payload = {\n min: data.analog_in_0,\n max: data.analog_in_1,\n mean: data.analog_in_2,\n std: data.analog_in_3\n}\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 420, "y": 100, "wires": [ [ "b9e1933908a6e7a2" ] ] }, { "id": "938f62da889d1c32", "type": "link in", "z": "0379d6b85cd091e6", "name": "", "links": [ "0ccfd39fce55e47b", "4806fc7172f307b1", "644f4c8b8ccabc60", "998fb78920616d2f", "b9e1933908a6e7a2" ], "x": 515, "y": 340, "wires": [ [ "b0f3e60a43f7d99a" ] ] }, { "id": "b0f3e60a43f7d99a", "type": "debug", "z": "0379d6b85cd091e6", "name": "", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 620, "y": 340, "wires": [] }, { "id": "bd971507f05f8f2a", "type": "ui_chart", "z": "0379d6b85cd091e6", "name": "", "group": "0f9f2919eea37f6f", "order": 1, "width": 12, "height": 11, "label": "chart", "chartType": "line", "legend": "true", "xformat": "HH:mm:ss", "interpolate": "linear", "nodata": "", "dot": false, "ymin": "", "ymax": "", "removeOlder": 1, "removeOlderPoints": "", "removeOlderUnit": "3600", "cutout": 0, "useOneColor": false, "useUTC": false, "colors": [ "#1f77b4", "#c01c28", "#ff7f0e", "#2ca02c", "#98df8a", "#aec7e8", "#ff9896", "#9467bd", "#c5b0d5" ], "outputs": 1, "useDifferentColor": false, "className": "", "x": 570, "y": 520, "wires": [ [] ] }, { "id": "dfa4182eed238352", "type": "split", "z": "0379d6b85cd091e6", "name": "", "splt": "\\n", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "topic", "x": 430, "y": 520, "wires": [ [ "bd971507f05f8f2a" ] ] }, { "id": "1918a9db9abfcb72", "type": "link in", "z": "0379d6b85cd091e6", "name": "", "links": [ "644f4c8b8ccabc60" ], "x": 335, "y": 520, "wires": [ [ "dfa4182eed238352" ] ] }, { "id": "c467a0fe0721b1b6", "type": "comment", "z": "0379d6b85cd091e6", "name": "Dashboard Widget Example", "info": "", "x": 480, "y": 480, "wires": [] }, { "id": "1ab9691461215172", "type": "comment", "z": "0379d6b85cd091e6", "name": "Debug sensor data", "info": "", "x": 810, "y": 340, "wires": [] }, { "id": "090e2f38a2317158", "type": "comment", "z": "0379d6b85cd091e6", "name": "Debug incoming messages", "info": "", "x": 290, "y": 20, "wires": [] }, { "id": "15a6ed11e4709d39", "type": "inject", "z": "0379d6b85cd091e6", "name": "Clear chart", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "[]", "payloadType": "json", "x": 420, "y": 580, "wires": [ [ "bd971507f05f8f2a" ] ] }, { "id": "b0479d9283a99332", "type": "mqtt-broker", "name": "", "broker": "eu1.cloud.thethings.industries", "port": "8883", "tls": "", "clientid": "", "autoConnect": true, "usetls": true, "protocolVersion": "4", "keepalive": "60", "cleansession": true, "birthTopic": "", "birthQos": "0", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willPayload": "", "willMsg": {}, "sessionExpiry": "", "credentials": {} }, { "id": "0f9f2919eea37f6f", "type": "ui_group", "name": "Default", "tab": "6aa60a85c8c12573", "order": 1, "disp": true, "width": 12, "collapse": false, "className": "" }, { "id": "6aa60a85c8c12573", "type": "ui_tab", "name": "Home", "icon": "dashboard", "disabled": false, "hidden": false } ] ``` <!-- # MPU6050 Accelerometer & Gyroscope ```python= from rak811.rak811 import Mode, Rak811 import RPi.GPIO as GPIO from time import sleep from cayennelpp import LppFrame from mpu6050 import mpu6050 import math import time # initialize GPIO GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.cleanup() # Initialize RAK811 LoRa module lora = Rak811() lora.hard_reset() lora.mode = Mode.LoRaWan lora.band = 'EU868' # Configure TTN credentials lora.set_config(app_eui='0101010101010101', app_key='' ) # Join TTN LoRaWAN lora.join_otaa() lora.dr = 5 # Initialise Accelerometer & Gyroscope sensor = mpu6050(0x68) # Generate a list of statistics about a collection of datasets def describe(collection): stats = {} for name, samples in collection.items(): n = len(samples) mean = sum(samples) / n std = math.sqrt(sum((s-mean)**2 for s in samples) / n) stats[name] = { "min": min(samples), "max": max(samples), "mean": mean, "std": std } return stats # Generate a list of samples of accelerometer and gyroscope readings # over a given duration def sample_IMU(sample_duration=1): t_start = time.time() samples = { "ax": [], "ay": [], "az": [], "rx": [], "ry": [], "rz": [] } while time.time() < t_start + sample_duration: acc = sensor.get_accel_data() gyr = sensor.get_gyro_data() samples['ax'].append(acc['x']) samples['ay'].append(acc['y']) samples['az'].append(acc['z']) samples['rx'].append(gyr['x']) samples['ry'].append(gyr['y']) samples['rz'].append(gyr['z']) return samples # Read and publish sensor data forever while True: # Create a Cayenne data frame frame = LppFrame() # Sample Accelerometer and Gyroscope for 15 seconds samples = sample_IMU(15) # Extract statistics from data sample stats = describe(samples) # Display statistics about sensor readings print(stats) # Add statistics to data frame frame.add_accelerometer(0, stats['ax']['min'], stats['ay']['min'], stats['az']['min']) frame.add_accelerometer(1, stats['ax']['max'], stats['ay']['max'], stats['az']['max']) frame.add_accelerometer(2, stats['ax']['mean'], stats['ay']['mean'], stats['az']['mean']) frame.add_accelerometer(3, stats['ax']['std'], stats['ay']['std'], stats['az']['std']) frame.add_gyrometer(0, stats['rx']['min'], stats['ry']['min'], stats['rz']['min']) frame.add_gyrometer(1, stats['rx']['max'], stats['ry']['max'], stats['rz']['max']) frame.add_gyrometer(2, stats['rx']['mean'], stats['ry']['mean'], stats['rz']['mean']) frame.add_gyrometer(3, stats['rx']['std'], stats['ry']['std'], stats['rz']['std']) # Publish data frame to TTN print("Publishing to TTN") lora.send(bytes(frame)) lora.close() ``` -->