diff --git a/2-farm/lessons/5-migrate-application-to-the-cloud/README.md b/2-farm/lessons/5-migrate-application-to-the-cloud/README.md index 5fcbacb..8236581 100644 --- a/2-farm/lessons/5-migrate-application-to-the-cloud/README.md +++ b/2-farm/lessons/5-migrate-application-to-the-cloud/README.md @@ -192,6 +192,23 @@ The Azure Functions CLI can be used to create a new Functions app. > ⚠️ If you get a firewall notification, grant access as the `func` application needs to be able to read and write to your network. + > ⚠️ If you are using macOS, there may be warnings in the output: + > + > ```output + > (.venv) ➜ soil-moisture-trigger func start + > Found Python version 3.9.1 (python3). + > + > Azure Functions Core Tools + > Core Tools Version: 3.0.3442 Commit hash: 6bfab24b2743f8421475d996402c398d2fe4a9e0 (64-bit) + > Function Runtime Version: 3.0.15417.0 + > + > [2021-06-16T08:18:28.315Z] Cannot create directory for shared memory usage: /dev/shm/AzureFunctions + > [2021-06-16T08:18:28.316Z] System.IO.FileSystem: Access to the path '/dev/shm/AzureFunctions' is denied. Operation not permitted. + > [2021-06-16T08:18:30.361Z] No job functions found. + > ``` + > + > You can ignore these as long as the Functions app starts correctly and lists the running functions. As mentioned in [this question on the Microsoft Docs Q&A](https://docs.microsoft.com/answers/questions/396617/azure-functions-core-tools-error-osx-devshmazurefu.html?WT.mc_id=academic-17441-jabenn) it can be ignored. + 1. Stop the Functions app by pressing `ctrl+c`. 1. Open the current folder in VS Code, either by opening VS Code, then opening this folder, or by running the following: @@ -213,23 +230,6 @@ The Azure Functions CLI can be used to create a new Functions app. 1. Make sure the Python virtual environment is running in the VS Code terminal. Terminate it and restart it if necessary. -1. There may be warnings in the output: - - ```output - (.venv) ➜ soil-moisture-trigger func start - Found Python version 3.9.1 (python3). - - Azure Functions Core Tools - Core Tools Version: 3.0.3442 Commit hash: 6bfab24b2743f8421475d996402c398d2fe4a9e0 (64-bit) - Function Runtime Version: 3.0.15417.0 - - [2021-06-16T08:18:28.315Z] Cannot create directory for shared memory usage: /dev/shm/AzureFunctions - [2021-06-16T08:18:28.316Z] System.IO.FileSystem: Access to the path '/dev/shm/AzureFunctions' is denied. Operation not permitted. - [2021-06-16T08:18:30.361Z] No job functions found. - ``` - - but don't worry about them as long as the Functions app starts correctly and lists the running functions. As mentioned in this question on the [Docs Q&A](https://docs.microsoft.com/answers/questions/396617/azure-functions-core-tools-error-osx-devshmazurefu.html?WT.mc_id=academic-17441-jabenn) it can be ignored. - ## Create an IoT Hub event trigger The Functions app is the shell of your serverless code. To respond to IoT hub events, you can add an IoT Hub trigger to this app. This trigger needs to connect to the stream of messages that are sent to the IoT Hub and respond to them. To get this stream of messages, your trigger needs to connect to the IoT Hubs *event hub compatible endpoint*. diff --git a/3-transport/lessons/1-location-tracking/code-gps-decode/pi/gps-sensor/app.py b/3-transport/lessons/1-location-tracking/code-gps-decode/pi/gps-sensor/app.py index 3aad986..a5de919 100644 --- a/3-transport/lessons/1-location-tracking/code-gps-decode/pi/gps-sensor/app.py +++ b/3-transport/lessons/1-location-tracking/code-gps-decode/pi/gps-sensor/app.py @@ -2,21 +2,12 @@ import time import serial import pynmea2 import json -from azure.iot.device import IoTHubDeviceClient, Message - -connection_string = '' serial = serial.Serial('/dev/ttyAMA0', 9600, timeout=1) serial.reset_input_buffer() serial.flush() -device_client = IoTHubDeviceClient.create_from_connection_string(connection_string) - -print('Connecting') -device_client.connect() -print('Connected') - -def printGPSData(line): +def print_gps_data(line): msg = pynmea2.parse(line) if msg.sentence_type == 'GGA': lat = pynmea2.dm_to_sd(msg.lat) @@ -28,16 +19,13 @@ def printGPSData(line): if msg.lon_dir == 'W': lon = lon * -1 - message_json = { "gps" : { "lat":lat, "lon":lon } } - print("Sending telemetry", message_json) - message = Message(json.dumps(message_json)) - device_client.send_message(message) + print(f'{lat},{lon} - from {msg.num_sats} satellites') while True: line = serial.readline().decode('utf-8') while len(line) > 0: - printGPSData(line) + print_gps_data(line) line = serial.readline().decode('utf-8') time.sleep(1) diff --git a/3-transport/lessons/1-location-tracking/code-gps-decode/virtual-device/gps-sensor/app.py b/3-transport/lessons/1-location-tracking/code-gps-decode/virtual-device/gps-sensor/app.py index 0383f8f..2b819a5 100644 --- a/3-transport/lessons/1-location-tracking/code-gps-decode/virtual-device/gps-sensor/app.py +++ b/3-transport/lessons/1-location-tracking/code-gps-decode/virtual-device/gps-sensor/app.py @@ -5,18 +5,11 @@ import time import counterfit_shims_serial import pynmea2 import json -from azure.iot.device import IoTHubDeviceClient, Message connection_string = '' serial = counterfit_shims_serial.Serial('/dev/ttyAMA0') -device_client = IoTHubDeviceClient.create_from_connection_string(connection_string) - -print('Connecting') -device_client.connect() -print('Connected') - def send_gps_data(line): msg = pynmea2.parse(line) if msg.sentence_type == 'GGA': @@ -29,10 +22,7 @@ def send_gps_data(line): if msg.lon_dir == 'W': lon = lon * -1 - message_json = { "gps" : { "lat":lat, "lon":lon } } - print("Sending telemetry", message_json) - message = Message(json.dumps(message_json)) - device_client.send_message(message) + print(f'{lat},{lon} - from {msg.num_sats} satellites') while True: line = serial.readline().decode('utf-8') @@ -41,4 +31,4 @@ while True: send_gps_data(line) line = serial.readline().decode('utf-8') - time.sleep(60) \ No newline at end of file + time.sleep(1) \ No newline at end of file diff --git a/3-transport/lessons/1-location-tracking/code-gps/pi/gps-sensor/app.py b/3-transport/lessons/1-location-tracking/code-gps/pi/gps-sensor/app.py index 8a282ee..0dfad1e 100644 --- a/3-transport/lessons/1-location-tracking/code-gps/pi/gps-sensor/app.py +++ b/3-transport/lessons/1-location-tracking/code-gps/pi/gps-sensor/app.py @@ -5,14 +5,14 @@ serial = serial.Serial('/dev/ttyAMA0', 9600, timeout=1) serial.reset_input_buffer() serial.flush() -def printGPSData(): +def print_gps_data(): print(line.rstrip()) while True: line = serial.readline().decode('utf-8') while len(line) > 0: - printGPSData() + print_gps_data() line = serial.readline().decode('utf-8') time.sleep(1) diff --git a/3-transport/lessons/1-location-tracking/code-gps/virtual-device/gps-sensor/app.py b/3-transport/lessons/1-location-tracking/code-gps/virtual-device/gps-sensor/app.py index 7dd2a96..811ffde 100644 --- a/3-transport/lessons/1-location-tracking/code-gps/virtual-device/gps-sensor/app.py +++ b/3-transport/lessons/1-location-tracking/code-gps/virtual-device/gps-sensor/app.py @@ -6,14 +6,14 @@ import counterfit_shims_serial serial = counterfit_shims_serial.Serial('/dev/ttyAMA0') -def printGPSData(line): +def print_gps_data(line): print(line.rstrip()) while True: line = serial.readline().decode('utf-8') while len(line) > 0: - printGPSData(line) + print_gps_data(line) line = serial.readline().decode('utf-8') time.sleep(1) \ No newline at end of file diff --git a/3-transport/lessons/1-location-tracking/pi-gps-sensor.md b/3-transport/lessons/1-location-tracking/pi-gps-sensor.md index 8cf3073..01148da 100644 --- a/3-transport/lessons/1-location-tracking/pi-gps-sensor.md +++ b/3-transport/lessons/1-location-tracking/pi-gps-sensor.md @@ -118,14 +118,14 @@ Program the device. serial.reset_input_buffer() serial.flush() - def printGPSData(line): + def print_gps_data(line): print(line.rstrip()) while True: line = serial.readline().decode('utf-8') while len(line) > 0: - printGPSData(line) + print_gps_data(line) line = serial.readline().decode('utf-8') time.sleep(1) @@ -133,9 +133,9 @@ Program the device. This code imports the `serial` module from the `pyserial` Pip package. It then connects to the `/dev/ttyAMA0` serial port - this is the address of the serial port that the Grove Pi Base Hat uses for its UART port. It then clears any existing data from this serial connection. - Next a function called `printGPSData` is defined that prints out the line passed to it to the console. + Next a function called `print_gps_data` is defined that prints out the line passed to it to the console. - Next the code loops forever, reading as many lines of text as it can from the serial port in each loop. It calls the `printGPSData` function for each line. + Next the code loops forever, reading as many lines of text as it can from the serial port in each loop. It calls the `print_gps_data` function for each line. After all the data has been read, the loop sleeps for 1 second, then tries again. diff --git a/3-transport/lessons/1-location-tracking/single-board-computer-gps-decode.md b/3-transport/lessons/1-location-tracking/single-board-computer-gps-decode.md index bf7bc26..3995462 100644 --- a/3-transport/lessons/1-location-tracking/single-board-computer-gps-decode.md +++ b/3-transport/lessons/1-location-tracking/single-board-computer-gps-decode.md @@ -24,7 +24,7 @@ Program the device to decode the GPS data. import pynmea2 ``` -1. Replace the contents of the `printGPSData` function with the following: +1. Replace the contents of the `print_gps_data` function with the following: ```python msg = pynmea2.parse(line) diff --git a/3-transport/lessons/1-location-tracking/virtual-device-gps-sensor.md b/3-transport/lessons/1-location-tracking/virtual-device-gps-sensor.md index e47a455..a524c7b 100644 --- a/3-transport/lessons/1-location-tracking/virtual-device-gps-sensor.md +++ b/3-transport/lessons/1-location-tracking/virtual-device-gps-sensor.md @@ -77,22 +77,22 @@ Program the GPS sensor app. 1. Add the following code below this to read from the serial port and print the values to the console: ```python - def printGPSData(line): + def print_gps_data(line): print(line.rstrip()) while True: line = serial.readline().decode('utf-8') while len(line) > 0: - printGPSData(line) + print_gps_data(line) line = serial.readline().decode('utf-8') time.sleep(1) ``` - A function called `printGPSData` is defined that prints out the line passed to it to the console. + A function called `print_gps_data` is defined that prints out the line passed to it to the console. - Next the code loops forever, reading as many lines of text as it can from the serial port in each loop. It calls the `printGPSData` function for each line. + Next the code loops forever, reading as many lines of text as it can from the serial port in each loop. It calls the `print_gps_data` function for each line. After all the data has been read, the loop sleeps for 1 second, then tries again. diff --git a/3-transport/lessons/2-store-location-data/code/pi/gps-sensor/app.py b/3-transport/lessons/2-store-location-data/code/pi/gps-sensor/app.py index a0b5c0c..3364f6b 100644 --- a/3-transport/lessons/2-store-location-data/code/pi/gps-sensor/app.py +++ b/3-transport/lessons/2-store-location-data/code/pi/gps-sensor/app.py @@ -1,13 +1,14 @@ import time -from grove.adc import ADC -from grove.grove_relay import GroveRelay +import serial +import pynmea2 import json -from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse +from azure.iot.device import IoTHubDeviceClient, Message connection_string = '' -adc = ADC() -relay = GroveRelay(5) +serial = serial.Serial('/dev/ttyAMA0', 9600, timeout=1) +serial.reset_input_buffer() +serial.flush() device_client = IoTHubDeviceClient.create_from_connection_string(connection_string) @@ -15,24 +16,28 @@ print('Connecting') device_client.connect() print('Connected') -def handle_method_request(request): - print("Direct method received - ", request.name) - - if request.name == "relay_on": - relay.on() - elif request.name == "relay_off": - relay.off() +def print_gps_data(line): + msg = pynmea2.parse(line) + if msg.sentence_type == 'GGA': + lat = pynmea2.dm_to_sd(msg.lat) + lon = pynmea2.dm_to_sd(msg.lon) - method_response = MethodResponse.create_from_method_request(request, 200) - device_client.send_method_response(method_response) + if msg.lat_dir == 'S': + lat = lat * -1 -device_client.on_method_request_received = handle_method_request + if msg.lon_dir == 'W': + lon = lon * -1 + + message_json = { "gps" : { "lat":lat, "lon":lon } } + print("Sending telemetry", message_json) + message = Message(json.dumps(message_json)) + device_client.send_message(message) while True: - soil_moisture = adc.read(0) - print("Soil moisture:", soil_moisture) + line = serial.readline().decode('utf-8') - message = Message(json.dumps({ 'soil_moisture': soil_moisture })) - device_client.send_message(message) + while len(line) > 0: + print_gps_data(line) + line = serial.readline().decode('utf-8') - time.sleep(10) \ No newline at end of file + time.sleep(60) diff --git a/3-transport/lessons/2-store-location-data/code/virtual-device/gps-sensor/app.py b/3-transport/lessons/2-store-location-data/code/virtual-device/gps-sensor/app.py index aa211db..0383f8f 100644 --- a/3-transport/lessons/2-store-location-data/code/virtual-device/gps-sensor/app.py +++ b/3-transport/lessons/2-store-location-data/code/virtual-device/gps-sensor/app.py @@ -2,15 +2,14 @@ from counterfit_connection import CounterFitConnection CounterFitConnection.init('127.0.0.1', 5000) import time -from counterfit_shims_grove.adc import ADC -from counterfit_shims_grove.grove_relay import GroveRelay +import counterfit_shims_serial +import pynmea2 import json -from azure.iot.device import IoTHubDeviceClient, Message, MethodResponse +from azure.iot.device import IoTHubDeviceClient, Message connection_string = '' -adc = ADC() -relay = GroveRelay(5) +serial = counterfit_shims_serial.Serial('/dev/ttyAMA0') device_client = IoTHubDeviceClient.create_from_connection_string(connection_string) @@ -18,24 +17,28 @@ print('Connecting') device_client.connect() print('Connected') -def handle_method_request(request): - print("Direct method received - ", request.name) - - if request.name == "relay_on": - relay.on() - elif request.name == "relay_off": - relay.off() +def send_gps_data(line): + msg = pynmea2.parse(line) + if msg.sentence_type == 'GGA': + lat = pynmea2.dm_to_sd(msg.lat) + lon = pynmea2.dm_to_sd(msg.lon) - method_response = MethodResponse.create_from_method_request(request, 200) - device_client.send_method_response(method_response) + if msg.lat_dir == 'S': + lat = lat * -1 -device_client.on_method_request_received = handle_method_request + if msg.lon_dir == 'W': + lon = lon * -1 + + message_json = { "gps" : { "lat":lat, "lon":lon } } + print("Sending telemetry", message_json) + message = Message(json.dumps(message_json)) + device_client.send_message(message) while True: - soil_moisture = adc.read(0) - print("Soil moisture:", soil_moisture) + line = serial.readline().decode('utf-8') - message = Message(json.dumps({ 'soil_moisture': soil_moisture })) - device_client.send_message(message) + while len(line) > 0: + send_gps_data(line) + line = serial.readline().decode('utf-8') - time.sleep(10) \ No newline at end of file + time.sleep(60) \ No newline at end of file diff --git a/6-consumer/lessons/4-multiple-language-support/README.md b/6-consumer/lessons/4-multiple-language-support/README.md index d92c80d..71542a9 100644 --- a/6-consumer/lessons/4-multiple-language-support/README.md +++ b/6-consumer/lessons/4-multiple-language-support/README.md @@ -2,7 +2,9 @@ Add a sketchnote if possible/appropriate -![Embed a video here if available](video-url) +This video gives an overview of the Azure speech services, covering speech to text and text to speech from earlier lessons, as well as translating speech, a topic covered in this lesson: + +[![Recognizing speech with a few lines of Python from Microsoft Build 2020](https://img.youtube.com/vi/h6xbpMPSGEA/0.jpg)](https://www.youtube.com/watch?v=h6xbpMPSGEA) ## Pre-lecture quiz diff --git a/README.md b/README.md index 316bce9..8640308 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ The projects cover the journey of food from farm to table. This includes farming ![A road map for the course showing 24 lessons covering intro, farming, transport, processing, retail and cooking](sketchnotes/Roadmap.png) -**Hearty thanks to our authors [Jen Fox](https://github.com/jenfoxbot), [Jen Looper](https://github.com/jlooper), [Jim Bennett](https://github.com/jimbobbennett), and our sketchnote artist [Nitya Narasimhan](https://github.com/nitya)** +**Hearty thanks to our authors [Jen Fox](https://github.com/jenfoxbot), [Jen Looper](https://github.com/jlooper), [Jim Bennett](https://github.com/jimbobbennett), and our sketchnote artist [Nitya Narasimhan](https://github.com/nitya).** -**Thanks as well to our team of [Microsoft Learn Student Ambassadors](https://studentambassadors.microsoft.com?WT.mc_id=academic-17441-jabenn) who have been reviewing and translating this curriculum - [Manvi Jha](https://github.com/Severus-Matthew), [Mireille Tan](https://www.linkedin.com/in/mireille-tan-a4834819a/), [Mohammad Iftekher (Iftu) Ebne Jalal](https://github.com/Iftu119), [Priyanshu Srivastav](https://www.linkedin.com/in/priyanshu-srivastav-b067241ba), and [Zina Kamel](https://www.linkedin.com/in/zina-kamel/)** +**Thanks as well to our team of [Microsoft Learn Student Ambassadors](https://studentambassadors.microsoft.com?WT.mc_id=academic-17441-jabenn) who have been reviewing and translating this curriculum - [Bhavesh Suneja](https://github.com/EliteWarrior315), [Lateefah Bello](https://www.linkedin.com/in/lateefah-bello/), [Manvi Jha](https://github.com/Severus-Matthew), [Mireille Tan](https://www.linkedin.com/in/mireille-tan-a4834819a/), [Mohammad Iftekher (Iftu) Ebne Jalal](https://github.com/Iftu119), [Priyanshu Srivastav](https://www.linkedin.com/in/priyanshu-srivastav-b067241ba), and [Zina Kamel](https://www.linkedin.com/in/zina-kamel/).** > **Teachers**, we have [included some suggestions](for-teachers.md) on how to use this curriculum. If you would like to create your own lessons, we have also included a [lesson template](lesson-template/README.md). diff --git a/hardware.md b/hardware.md index 77e8070..007e2c9 100644 --- a/hardware.md +++ b/hardware.md @@ -46,7 +46,7 @@ All the device code for Raspberry Pi is in Python. To complete all the assignmen These are specific to using the Raspberry Pi, and are not relevant to using the Arduino device. -* [Grove Pi base hat](https://wiki.seeedstudio.com/Grove_Base_Hat_for_Raspberry_Pi) +* [Grove Pi base hat](https://www.seeedstudio.com/Grove-Base-Hat-for-Raspberry-Pi.html) * [Raspberry Pi Camera module](https://www.raspberrypi.org/products/camera-module-v2/) * Microphone and speaker: