Merging in everything from previous repo (#6)
* Adding content * Update en.json * Update README.mdpull/40/head
parent
6684b00c36
commit
14fefbed47
@ -1,350 +1,9 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
.DS_Store
|
||||
.venv
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
.ipynb_checkpoints
|
||||
|
@ -0,0 +1,16 @@
|
||||
# Getting Started with IoT
|
||||
|
||||
In this section of the curriculum, you will be introduced to the Internet of Things, and learn the basic concepts including building your first 'Hello World' IoT project connecting to the cloud. This project is a nightlight that lights up as light levels measured by a sensor drop.
|
||||
|
||||

|
||||
|
||||
## Topics
|
||||
|
||||
1. [Introduction to IoT](lessons/1-introduction-to-iot/README.md)
|
||||
1. [A deeper dive into IoT](lessons/2-deeper-dive/README.md)
|
||||
1. [Interact with the physical world with sensors and actuators](lessons/3-sensors-and-actuators/README.md)
|
||||
1. [Connect your device to the Internet](lessons/4-connect-internet/README.md)
|
||||
|
||||
## Credits
|
||||
|
||||
All the lessons were written with ♥️ by [Jim Bennett](https://GitHub.com/JimBobBennett)
|
@ -0,0 +1,222 @@
|
||||
# Introduction to IoT
|
||||
|
||||
Add a sketchnote if possible/appropriate
|
||||
|
||||

|
||||
|
||||
## Pre-lecture quiz
|
||||
|
||||
[Pre-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/1)
|
||||
|
||||
## Introduction
|
||||
|
||||
This lesson covers some of the introductory topics around the Internet of Things, and gets you going setting up your hardware.
|
||||
|
||||
In this lesson we'll cover:
|
||||
|
||||
* [What is the 'Internet of Things'?](#what-is-the-internet-of-things)
|
||||
* [IoT devices](#iot-devices)
|
||||
* [Set up your device](#set-up-your-device)
|
||||
* [Applications of IoT](#applications-of-iot)
|
||||
* [Examples of IoT devices you may have around you](#examples-of-iot-devices-you-may-have-around-you)
|
||||
|
||||
## What is the 'Internet of Things'?
|
||||
|
||||
The term 'Internet of Things' was coined by [Kevin Ashton](https://wikipedia.org/wiki/Kevin_Ashton) in 1999 to refer to connecting the Internet to the physical world via sensors. Since then the term has been used to describe any device that interacts with the physical world around it either by gathering data from sensors, or providing real-world interactions via actuators (devices that do something like turn on a switch or light an LED), generally connected to other devices or the Internet.
|
||||
|
||||
> **Sensors** gather information from the world, such as measuring speed, temperature or location.
|
||||
>
|
||||
> **Actuators** convert electrical signals into real-world interactions such as levers, turning on lights, making sounds, or sending control signals to other hardware such as to turn on a power socket
|
||||
|
||||
IoT as a technology area is more than just devices - it includes cloud based services that can process the sensor data, or send requests to actuators connected to IoT devices. It also includes devices that don't have connectivity, often referred to as edge devices, that can process and respond to sensor data themselves, usually using AI models trained in the cloud.
|
||||
|
||||
IoT is a fast growing technology field. It is estimated that by the end of 2020, 30 billion IoT devices were deployed and connected to the Internet. Looking to the future, it is estimated that by 2025, IoT devices will be gathering almost 80 zettabytes of data, or 80 trillion gigabytes. That's a lot of data!
|
||||
|
||||

|
||||
|
||||
✅ Do a little research: how much of the data generated by IoT devices is actually used, and how much is wasted? Why is so much data ignored?
|
||||
|
||||
This data is the key to IoT's success. To be a successful IoT developer, you need to understand the data you need to gather, how to gather it, how to make decisions based off it, and how to use those decisions to interact back with the physical world if needed.
|
||||
|
||||
## IoT devices
|
||||
|
||||
The **T** in IoT stands for **Things** - devices that interact with the physical world around them either by gathering data from sensors, or providing real-world interactions via actuators.
|
||||
|
||||
Devices for production or commercial use, such as the consumer fitness trackers, or industrial machine controllers, are usually custom made. They use custom circuit boards, maybe even custom processors, designed to meet the needs of a particular task, whether that's being small enough to fit on a wrist, or rugged enough to work in a high temperature, high stress, high vibration factory environment.
|
||||
|
||||
As a developer, either learning about IoT or creating a prototype device, you'll need to start with a developer kit. These are general purpose IoT devices designed for developers to use, often with features that you wouldn't see on a production device, such as a set of external pins to connect sensors or actuators to, hardware to support debugging, or additional resources that would add unnecessary cost when doing a large manufacturing run.
|
||||
|
||||
These developer kits usually fall into two categories - microcontrollers and single-board computers. These will be introduced here, and we'll go into them in more detail in the next lesson.
|
||||
|
||||
> 💁 Your phone can also be considered to be a general-purpose IoT device, with sensors and actuators built in, with different apps using the sensors and actuators in different ways with different cloud services. You can even find some IoT tutorials that use a phone app as an IoT device.
|
||||
|
||||
### Microcontrollers
|
||||
|
||||
A microcontroller (also referred to as an MCU, short for microcontroller unit) is a small computer consisting of:
|
||||
|
||||
🧠 One or more central processing units (CPUs) - the 'brain' of the microcontroller that runs your program
|
||||
|
||||
💾 Memory (RAM and program memory) - where your program, data, and variables are stored
|
||||
|
||||
🔌 Programmable input/output (I/O) connections - to talk to external peripherals (connected devices) such as sensors or actuators
|
||||
|
||||
Microcontrollers are typically low cost computing devices, with average prices for the ones used in custom hardware dropping to around US$0.50, with some devices as cheap as US$0.03. Developer kits can start as low as US$4, with costs rising as you add more features. The [Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html), a microcontroller developer kit from [Seeed studios](https://www.seeedstudio.com) that has sensors, actuators, WiFi and a screen costs around US$30.
|
||||
|
||||

|
||||
|
||||
> 💁 When searching the Internet for microcontrollers be wary of searching for the term **MCU** as this will bring back a lot of results for the Marvel Cinematic Universe, not microcontrollers.
|
||||
|
||||
Microcontrollers are designed to be programmed to do a limited number of very specific tasks, rather than being general-purpose computers like PCs or Macs. Except for very specific scenarios, you can't connect a monitor, keyboard and mouse and use them for general purpose tasks.
|
||||
|
||||
Microcontroller developer kits usually come with additional sensors and actuators on board. Most boards will have one or more LEDs you can program, along with other devices such as standard plugs for adding more sensors or actuators using various manufacturers ecosystems or built in sensors (usually the most popular ones such as temperature). Some microcontrollers have built in wireless connectivity such as Bluetooth or WiFi, or have additional microcontrollers on the board to add this connectivity.
|
||||
|
||||
> 💁 Microcontrollers are usually programmed in C/C++.
|
||||
|
||||
### Single-board computers
|
||||
|
||||
A single-board computer is a small computing devices that has all the elements of a complete computer contained on a single small board. These are devices that have specifications close to a desktop or laptop PC or Mac, run a full operating system, but are small, use lower power, and are substantially cheaper.
|
||||
|
||||

|
||||
|
||||
***Raspberry Pi 4. Michael Henzler / [Wikimedia Commons](https://commons.wikimedia.org/wiki/Main_Page) / [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)***
|
||||
|
||||
The Raspberry Pi is one of the most popular single-board computers.
|
||||
|
||||
Like a microcontroller, single-board computers have a CPU, memory and input/output pins, but they have additional features such as a graphics chip to allow you to connect monitors, audio outputs, and USB ports to connect keyboards mice and other standard USB devices like webcams or external storage. Programs are stored on SD cards or hard drives along with an operating system, instead of a memory chip built into the board.
|
||||
|
||||
> 🎓 You can think of a single-board computer as a smaller, cheaper version of the PC or Mac you are reading this on, with the addition of GPIO pins to interact with sensors and actuators.
|
||||
|
||||
SIngle-board computers are fully-featured computers, so can be programmed in any language. IoT devices are typically programmed in Python.
|
||||
|
||||
### Hardware choices for the rest of the lessons
|
||||
|
||||
All the subsequent lessons include assignments using an IoT device to interact with the physical world, and communicate with the cloud. Each lesson supports 3 device choices - Arduino (using a Seeed Studios Wio Terminal), or a single-board computer, either a physical device (a Raspberry Pi 4), or a virtual single-board computer running on your PC or Mac.
|
||||
|
||||
You can read about the hardware needed to complete all the assignments in the [hardware guide](../../hardware.md).
|
||||
|
||||
> 💁 You don't need to purchase any IoT hardware to complete the assignments, you can do everything using a virtual single-board computer.
|
||||
|
||||
Which hardware you choose is up to you - it depends on what you have available either at home on in your school, and what programming language you know or plan to learn. Both hardware variants will use the same sensor ecosystem, so if you start down one path, you can change to the other without having to replace most of the kit. The virtual single-board computer will be the equivalent of learning on a Raspberry Pi, with most of the code transferrable to the Pi if you eventually get a device and sensors.
|
||||
|
||||
### Arduino developer kit
|
||||
|
||||
If you are interested in learning microcontroller development, you can complete the assignments using an Arduino device. You will need a basic understanding of C/C++ programming, as the lessons will only teach code that is relevant to the Arduino framework, the sensors and actuators being used, and the libraries that interact with the cloud.
|
||||
|
||||
The assignments will use [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-17441-jabenn) with the [PlatformIO extension for microcontroller development](https://platformio.org). You can also use the Arduino IDE if you are experienced with this tool, as instructions will not be provided.
|
||||
|
||||
### Single-board computer developer kit
|
||||
|
||||
If you are interested in learning IoT development using single-board computers, you can complete the assignments using a Raspberry Pi, or a virtual device running on your PC or Mac.
|
||||
|
||||
You will need a basic understanding of Python programming, as the lessons will only teach code that is relevant to the sensors and actuators being used, and the libraries that interact with the cloud.
|
||||
|
||||
> 💁 If you want to learn to code in Python, check out the following two video series:
|
||||
>
|
||||
> * [Python for beginners](https://channel9.msdn.com/Series/Intro-to-Python-Development?WT.mc_id=academic-17441-jabenn)
|
||||
> * [More Python for beginners](https://channel9.msdn.com/Series/More-Python-for-Beginners?WT.mc_id=academic-7372-jabenn)
|
||||
|
||||
The assignments will use [Visual Studio Code](https://code.visualstudio.com/?WT.mc_id=academic-17441-jabenn).
|
||||
|
||||
If you are using a Raspberry Pi, you can either run your Pi using the full desktop version of Raspberry Pi OS, and do all the coding directly on the Pi using [the Raspberry Pi OS version of VS Code](https://code.visualstudio.com/docs/setup/raspberry-pi?WT.mc_id=academic-17441-jabenn), or run your Pi as a headless device and code from your PC or Mac using VS Code with the [Remote SSH extension](https://code.visualstudio.com/docs/remote/ssh?WT.mc_id=academic-17441-jabenn) that allows you to connect to your Pi and edit, debug and run code as if you were coding on it directly.
|
||||
|
||||
If you use the virtual device option, you will code directly on your computer. Instead of accessing sensors and actuators, you will use a tool to simulate this hardware providing sensor values that you can define, and showing the results of actuators on screen.
|
||||
|
||||
## Set up your device
|
||||
|
||||
Before you can get started with programming your IoT device, you will need to do a small amount of setup. Follow the relevant instructions below depending on which device you will be using.
|
||||
|
||||
> 💁 If you don't have a device yet, refer to the [hardware guide](../../../hardware.md) to help decide which device you are going to use, and what additional hardware you need to purchase. You don't need to purchase hardware, as all the projects can be run on virtual hardware.
|
||||
|
||||
These instructions do include links to third-party websites from the creators of the hardware or tools you will be using. This is to ensure you are always using the most up-to-date instructions for the various tools and hardware.
|
||||
|
||||
Work through the relevant guide to set your device up and complete a 'Hello World' project. This will be the first step in creating an IoT nightlight over the 4 lessons in this getting started part.
|
||||
|
||||
* [Arduino - Wio Terminal](wio-terminal.md)
|
||||
* [Single-board computer - Raspberry Pi](pi.md)
|
||||
* [Single-board computer - Virtual device](virtual-device.md)
|
||||
|
||||
## Applications of IoT
|
||||
|
||||
IoT covers a huge range of use cases, across a few broad groups:
|
||||
|
||||
* Consumer IoT
|
||||
* Commercial IoT
|
||||
* Industrial IoT
|
||||
* Infrastructure IoT
|
||||
|
||||
✅ Do a little research: For each of the areas described below, find one concrete example that's not given in the text.
|
||||
|
||||
### Consumer IoT
|
||||
|
||||
Consumer IoT refers to IoT devices that consumers will buy and use around the home. Some of these devices are incredibly useful, such as smart speakers, smart heating systems and robotic vacuum cleaners. Others are questionable in their usefulness, such as voice controlled taps that then mean you cannot turn them off as the voice control cannot hear you over the sound of running water.
|
||||
|
||||
Consumer IoT devices are empowering people to achieve more in their surroundings, especially the 1 billion who have a disability. Robotic vacuum cleaners can provide clean floors to people with mobility issues who cannot vacuum themselves, voice controlled ovens allow people with limited vision or motor control to heat their ovens with only their voice, health monitors can allow patients to monitor chronic conditions themselves with more regular and more detailed updates on their conditions. These devices are becoming so ubiquitous that even young children are using them as part of their daily lives, for example students doing virtual schooling during the COVID pandemic setting timers on smart home devices to track their schoolwork or alarms to remind them of upcoming class meetings.
|
||||
|
||||
✅ What consumer IoT devices do you have on your person or in your home?
|
||||
|
||||
### Commercial IoT
|
||||
|
||||
Commercial IoT covers the use of IoT in the workplace. In an office setting there may be occupancy sensors and motion detectors to manage lighting and heating to only keep the lights and heat off when not needed, reducing cost and carbon emissions. In a factory, IoT devices can monitor for safety hazards such as workers not wearing hard hats or noise that has reached dangerous levels. In retail, IoT devices can measure the temperature of cold storage, alerting the shop owner if a fridge or freezer is outside the required temperature range, or they can monitor items on shelves to direct employees to refill produce that has been sold. The transport industry is relying more and more on IoT to monitor vehicle locations, track on-road mileage for road user charging, track driver hours and break compliance, or notify staff when a vehicle is approaching a depot to prepare for loading or unloading.
|
||||
|
||||
✅ What commercial IoT devices do you have in your school or workplace?
|
||||
|
||||
### Industrial IoT (IIoT)
|
||||
|
||||
Industrial IoT, or IIoT, is the use of IoT devices to control and manage machinery on a large scale. This covers a wide range of use cases, from factories to digital agriculture.
|
||||
|
||||
Factories use IoT devices in many different ways. Machinery can be monitored with multiple sensors to track things like temperature, vibration and rotation speed. This data can then be monitored to allow the machine to be stopped if it goes outside of certain tolerances - it runs to hot and gets shut down for example. This data can also be gathered and analyzed over time to do predictive maintenance, where AI models will look at the data leading up to a failure, and use that to predict other failures before they happen.
|
||||
|
||||
Digital agriculture is important if the planet is to feed the growing population, especially for the 2 billion people in 500 million households that survive on [subsistence farming](https://wikipedia.org/wiki/Subsistence_agriculture). Digital agriculture can range from a few single digit dollar sensors, to massive commercial setups. A farmer can start by monitoring temperatures and using [growing degree days](https://wikipedia.org/wiki/Growing_degree-day) to predict when a crop will be ready for harvest. They can connect soil moisture monitoring to automated watering systems to give their plants as much water as is needed, but no more to ensure their crops don't dry out without wasting water. Farmers are even taking it further and using drones, satellite data and AI to monitor crop growth, disease and soil quality over huge areas of farmland.
|
||||
|
||||
✅ What other IoT devices could help farmers?
|
||||
|
||||
### Infrastructure IoT
|
||||
|
||||
Infrastructure IoT is monitoring and controlling the local and global infrastructure that people use every day.
|
||||
|
||||
[Smart Cities](https://wikipedia.org/wiki/Smart_city) are urban areas that use IoT devices to gather data about the city and use that to improve how the city runs. These cities are usually run with collaborations between local governments, academia and local businesses, tracking and managing things varying from transport to parking and pollution. For example, in Copenhagen, Denmark, air pollution is important to the local residents, so it is measured and the data is used to provide information on the cleanest cycling and jogging routes.
|
||||
|
||||
[Smart power grids](https://wikipedia.org/wiki/Smart_grid) allow better analytics of power demand by gathering usage data at the level of individual homes. This data can guide decisions at a country level including where to build new power stations, and at a personal level by giving users insights into how much power they are using, when they are using it, and even suggestions on how to reduce costs, such as charging electric cars at night.
|
||||
|
||||
✅ If you could add IoT devices to measure anything where you live, what would it be?
|
||||
|
||||
## Examples of IoT devices you may have around you
|
||||
|
||||
You'd be amazed by just how many IoT devices you have around you. I'm writing this from home and I have the following devices connected to the Internet with smart features such as app control, voice control, or the ability to send data to me via my phone:
|
||||
|
||||
* Multiple smart speakers
|
||||
* Fridge, dishwasher, oven and microwave
|
||||
* Electricity monitor for solar panels
|
||||
* Smart plugs
|
||||
* Video doorbell and security cameras
|
||||
* Smart thermostat with multiple smart room sensors
|
||||
* Garage door opener
|
||||
* Home entertainment systems and voice controlled TVs
|
||||
* Lights
|
||||
* Fitness and health trackers
|
||||
|
||||
All these types of devices have sensors and/or actuators and talk to the Internet. I can tell from my phone if my garage door is open, and ask my smart speaker to close it for me. I can even set it to a timer so if it's still open at night, it will close automatically. When my doorbell rings, I can see from my phone who is there wherever I am in the world, and talk to them via a speaker and microphone built into the doorbell. I can monitor my blood glucose, heart rate and sleep patterns, looking for patterns in the data to improve my health. And I can control my lights via the cloud, and sit in the dark when my Internet connection goes down.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Challenge
|
||||
|
||||
List as many IoT devices as you can that are in your home, school or workplace - there may be more than you think!
|
||||
|
||||
## Post-lecture quiz
|
||||
|
||||
[Post-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/2)
|
||||
|
||||
## Review & Self Study
|
||||
|
||||
Read up on the benefits and failures of consumer IoT projects. Check news sites for articles on when it has gone wrong, such as privacy issues, hardware problems or problems caused by lack of connectivity.
|
||||
|
||||
Some examples:
|
||||
|
||||
* Check out the Twitter account **[Internet of Sh*t](https://twitter.com/internetofshit)** *(profanity warning)* for some good examples of failures with consumer IoT.
|
||||
* [c|net - My Apple Watch saved my life: 5 people share their stories](https://www.cnet.com/news/apple-watch-lifesaving-health-features-read-5-peoples-stories/)
|
||||
* [c|net - ADT technician pleads guilty to spying on customer camera feeds for years](https://www.cnet.com/news/adt-home-security-technician-pleads-guilty-to-spying-on-customer-camera-feeds-for-years/) *(trigger warning - non-consensual voyeurism)*
|
||||
|
||||
## Assignment
|
||||
|
||||
[Investigate an IoT project](assignment.md)
|
@ -0,0 +1,13 @@
|
||||
# Investigate an IoT project
|
||||
|
||||
## Instructions
|
||||
|
||||
There are many large and small scale IoT projects being rolled out globally, from smart farms to smart cities, healthcare monitoring, transport, or the use of public spaces.
|
||||
|
||||
Search the web for details of a project that interests you, ideally one close you where you live. Explain the upsides and the downsides of the project, such as what benefit comes from it, any problems it causes and how privacy is taken into consideration.
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| Explain the upsides and downsides | Gave a clear explanation of the upsides and downsides of the project | Gave a brief explanation of the upsides and downsides | Didn't explain the upsides or the downsides |
|
@ -0,0 +1 @@
|
||||
print('Hello World!')
|
@ -0,0 +1,5 @@
|
||||
from counterfit_connection import CounterFitConnection
|
||||
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
print('Hello World!')
|
@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
from counterfit_shims_grove.counterfit_connection import CounterFitConnection
|
||||
import time
|
||||
from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from counterfit_shims_grove.grove_led import GroveLed
|
||||
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
if light < 200:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
time.sleep(1)
|
@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
@ -0,0 +1,14 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:seeed_wio_terminal]
|
||||
platform = atmelsam
|
||||
board = seeed_wio_terminal
|
||||
framework = arduino
|
@ -0,0 +1,17 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
while (!Serial)
|
||||
; // Wait for Serial to be ready
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println("Hello World");
|
||||
delay(5000);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
@ -0,0 +1,247 @@
|
||||
# Raspberry Pi
|
||||
|
||||
The [Raspberry Pi](https://raspberrypi.org) is a single-board computer. You can add sensors and actuators using a wide range of devices and ecosystems, and for these lessons using a hardware ecosystem called [Grove](https://www.seeedstudio.com/category/Grove-c-1003.html). You will code your Pi and access the Grove sensors using Python.
|
||||
|
||||

|
||||
|
||||
***Raspberry Pi 4. Michael Henzler / [Wikimedia Commons](https://commons.wikimedia.org/wiki/Main_Page) / [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)***
|
||||
|
||||
## Setup
|
||||
|
||||
If you are using a Raspberry Pi as your IoT hardware, you have two choices - you can work through all these lessons and code directly on the Pi, or you can connect remotely to a 'headless' Pi and code from your computer.
|
||||
|
||||
Before you begin, you also need to connect the Grove Base Hat to your Pi.
|
||||
|
||||
### Task
|
||||
|
||||
Install the Grove base hat on your Pi and configure the Pi
|
||||
|
||||
1. Connect the Grove base hat to your Pi. The socket on the hat fits over all of the GPIO pins on the Pi, sliding all the way down the pins to sit firmly on the base. It sits over the Pi, covering it.
|
||||
|
||||

|
||||
|
||||
1. Decide how you want to program you Pi, and head to the relevant section below:
|
||||
|
||||
* [Work directly on your Pi](#work-directly-on-your-pi)
|
||||
* [Remote access to code the Pi](#remote-access-to-code-the-pi)
|
||||
|
||||
### Work directly on your Pi
|
||||
|
||||
If you want to work directly on your Pi, you can use the desktop version of Raspberry Pi OS and install all the tools you need.
|
||||
|
||||
#### Task
|
||||
|
||||
Set up your Pi for development.
|
||||
|
||||
1. Follow the instructions in the [Raspberry Pi setup guide](https://projects.raspberrypi.org/en/projects/raspberry-pi-setting-up) to set up your Pi, connect it to a keyboard/mouse/monitor, connect it to your WiFi or ethernet network, and update the software. The OS you want to install is **Raspberry Pi OS (32 bit)**, it is marked as the recommended OS when using the Raspberry Pi Imager to image your SD card.
|
||||
|
||||
To program the Pi using the Grove sensors and actuators, you will need to install an editor to allow you to write the device code, and various libraries and tools that interact with the Grove hardware.
|
||||
|
||||
1. Once your Pi has rebooted, launch the Terminal by clicking the **Terminal** icon on the top menu bar, or choose *Menu -> Accessories -> Terminal*
|
||||
|
||||
1. Run the following command to ensure the OS and installed software is up to date:
|
||||
|
||||
```sh
|
||||
sudo apt update && sudo apt full-upgrade --yes
|
||||
```
|
||||
|
||||
1. Run the following command to install all the needed libraries for the Grove hardware:
|
||||
|
||||
```sh
|
||||
curl -sL https://github.com/Seeed-Studio/grove.py/raw/master/install.sh | sudo bash -s -
|
||||
```
|
||||
|
||||
One of the powerful features of Python is the ability to install [pip packages](https://pypi.org) - these are packages of code written by other people and published to the Internet. You can install a pip package onto your computer with one command, then use that package in your code. This Grove install script will install the pip packages you will use to work with the Grove hardware from Python.
|
||||
|
||||
1. Reboot the Pi either using the menu, or running the following command in the Terminal:
|
||||
|
||||
```sh
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
1. Once the Pi has rebooted, relaunch the Terminal and run the following command to install [Visual Studio Code (VS Code)](https://code.visualstudio.com?WT.mc_id=academic-17441-jabenn) - this is the editor you will be using to write your device code in Python.
|
||||
|
||||
```sh
|
||||
sudo apt install code
|
||||
```
|
||||
|
||||
Once this is installed, VS Code will be available from the top menu.
|
||||
|
||||
> 💁 You are free to use any Python IDE or editor for these lessons if you have a preferred tool, but the lessons will give instructions based off using VS Code.
|
||||
|
||||
1. Install Pylance. This is an extension for VS Code that provides Python language support. Refer to the [Pylance extension documentation](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance&WT.mc_id=academic-17441-jabenn) for instructions on installing this extension in VS Code.
|
||||
|
||||
### Remote access to code the Pi
|
||||
|
||||
Rather than coding directly on the Pi, it can run 'headless', that is not connected to a keyboard/mouse/monitor, and configure and code on it from your computer, using Visual Studio Code.
|
||||
|
||||
#### Set up the Pi OS
|
||||
|
||||
To code remotely, the Pi OS needs to be installed on an SD Card.
|
||||
|
||||
##### Task
|
||||
|
||||
Set up the headless Pi OS.
|
||||
|
||||
1. Download the **Raspberry Pi Imager** from the [Raspberry Pi OS software page](https://www.raspberrypi.org/software/) and install it
|
||||
|
||||
1. Insert an SD card into your computer, using an adapter if necessary
|
||||
|
||||
1. Launch the Raspberry Pi Imager
|
||||
|
||||
1. From the Raspberry Pi Imager, select the **CHOOSE OS** button, then select *Raspberry Pi OS (Other)*, followed by *Raspberry Pi OS Lite (32-bit)*
|
||||
|
||||

|
||||
|
||||
> 💁 Raspberry Pi OS Lite is a version of Raspberry Pi OS that doesn't have the desktop UI, or UI based tools. These aren't needed for a headless Pi, and makes the install smaller and boot up time faster.
|
||||
|
||||
1. Select the **CHOOSE STORAGE** button, then select your SD card
|
||||
|
||||
1. Launch the **Advanced Options** by pressing `Ctrl+Shift+X`. These options allow some pre-configuration of the Raspberry Pi OS before it is imaged to the SD card.
|
||||
|
||||
1. Check the **Enable SSH** check box, and set a password for the `pi` user. This is the password you will use to log in to the Pi later.
|
||||
|
||||
1. If you are planning to connect to the Pi over WiFi, check the **Configure WiFi** check box, and enter your WiFi SSID and password, as well as selecting your WiFi country. You do not need to do this if you will use an ethernet cable. Make sure the network you connect to is the same one your computer is on.
|
||||
|
||||
1. Check the **Set locale settings** check box, and set your country and timezone
|
||||
|
||||
1. Select the **SAVE** button
|
||||
|
||||
1. Select the **WRITE** button to write the OS to the SD card. If you are using macOS, you will be asked to enter your password as the underlying tool that writes disk images needs privileged access.
|
||||
|
||||
The OS will be written to the SD card, and once compete the card will be ejected by the OS, and you will be notified. Remove the SD card from your computer, insert it into the Pi and power up the Pi.
|
||||
|
||||
#### Connect to the Pi
|
||||
|
||||
The next step is to remotely access the Pi. You can do this using `ssh`, which is available on macOS, Linux and recent versions of Windows.
|
||||
|
||||
##### Task
|
||||
|
||||
Remotely access the Pi.
|
||||
|
||||
1. Launch a Terminal or Command Prompt, and enter the following command to connect to the Pi:
|
||||
|
||||
```sh
|
||||
ssh pi@raspberrypi.local
|
||||
```
|
||||
|
||||
If you are on Windows using an older version that doesn't have `ssh` installed, you can use OpenSSH. You can find the installation instructions in the [OpenSSH installation documentation](https://docs.microsoft.com//windows-server/administration/openssh/openssh_install_firstuse?WT.mc_id=academic-17441-jabenn).
|
||||
|
||||
1. This should connect to your Pi and ask for the password.
|
||||
|
||||
Being able to find computers on your network by using `<hostname>.local` is a fairly recent addition to Linux and Windows. If you are using Linux or Windows and you get any errors about the Hostname not being found, you will need to install additional software to enable ZeroConf networking (also referred to by Apple as Bonjour):
|
||||
|
||||
1. If you are using Linux, install Avahi using the following command:
|
||||
|
||||
```sh
|
||||
sudo apt-get install avahi-daemon
|
||||
```
|
||||
|
||||
1. If you are using Windows, the easiest way to enable ZeroConf is to install [Bonjour Print Services for Windows](http://support.apple.com/kb/DL999). You can also install [iTunes for Windows](https://www.apple.com/itunes/download/) to get a newer version of the utility (which is not available standalone).
|
||||
|
||||
> 💁 If you cannot connect using `raspberrypi.local`, then you can use the IP address of your Pi. Refer to the [Raspberry Pi IP address documentation](https://www.raspberrypi.org/documentation/remote-access/ip-address.md) for instructions of a number of ways to get the IP address.
|
||||
|
||||
1. Enter the password you set in the Raspberry Pi Imager Advanced Options
|
||||
|
||||
#### Configure software on the Pi
|
||||
|
||||
Once you are connected to the Pi, you need to ensure the OS is up to date, and install various libraries and tools that interact with the Grove hardware.
|
||||
|
||||
##### Task
|
||||
|
||||
Configure the installed Pi software and install the Grove libraries.
|
||||
|
||||
1. From your `ssh` session, run the following command to update then reboot the Pi:
|
||||
|
||||
```sh
|
||||
sudo apt update && sudo apt full-upgrade --yes && sudo reboot
|
||||
```
|
||||
|
||||
The Pi will be updated and rebooted. The `ssh` session will end when the Pi is rebooted, so leave it about 30 seconds then reconnect.
|
||||
|
||||
1. From the reconnected `ssh` session, run the following command to install all the needed libraries for the Grove hardware:
|
||||
|
||||
```sh
|
||||
curl -sL https://github.com/Seeed-Studio/grove.py/raw/master/install.sh | sudo bash -s -
|
||||
```
|
||||
|
||||
One of the powerful features of Python is the ability to install [pip packages](https://pypi.org) - these are packages of code written by other people and published to the Internet. You can install a pip package onto your computer with one command, then use that package in your code. This Grove install script will install the pip packages you will use to work with the Grove hardware from Python.
|
||||
|
||||
1. Reboot the Pi by running the following command:
|
||||
|
||||
```sh
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
The `ssh` session will end when the Pi is rebooted. There is no need to reconnect.
|
||||
|
||||
#### Configure VS Code for remote access
|
||||
|
||||
Once the Pi is configured, you can connect to it using Visual Studio Code (VS Code) from your computer - this is a free developer text editor you will be using to write your device code in Python.
|
||||
|
||||
##### Task
|
||||
|
||||
Install the required software and connect remotely to your Pi.
|
||||
|
||||
1. Install VS Code on your computer by following the [VS Code documentation](https://code.visualstudio.com?WT.mc_id=academic-17441-jabenn)
|
||||
|
||||
1. Follow the instructions in the [VS Code Remote Development using SSH documentation](https://code.visualstudio.com/docs/remote/ssh?WT.mc_id=academic-17441-jabenn) to install the components needed
|
||||
|
||||
1. Following the same instructions, connect VS Code to the Pi
|
||||
|
||||
1. Once connected, follow the [managing extensions](https://code.visualstudio.com/docs/remote/ssh#_managing-extensions?WT.mc_id=academic-17441-jabenn) instructions to install the [Pylance extension](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance&WT.mc_id=academic-17441-jabenn) remotely onto the Pi
|
||||
|
||||
## Hello world
|
||||
|
||||
It is traditional when starting out with a new programming language or technology to create a 'Hello World' application - a small application that outputs something like the text `"Hello World"` to show that all the tools are correctly configured.
|
||||
|
||||
The Hello World app for the Pi will ensure that you have Python and Visual Studio code installed correctly.
|
||||
|
||||
This app will be in a folder called `nightlight`, and it will be re-used with different code in later parts of this assignment to build the nightlight application.
|
||||
|
||||
### Task
|
||||
|
||||
Create the Hello World app.
|
||||
|
||||
1. Launch VS Code, either directly on the Pi, or on your computer and connected to the Pi using the Remote SSH extension
|
||||
|
||||
1. Launch the VS Code Terminal by selecting *Terminal -> New Terminal, or pressing `` CTRL+` ``. It will open to the `pi` users home directory.
|
||||
|
||||
1. Run the following commands to create a directory for your code, and create a Python file called `app.py` inside that directory:
|
||||
|
||||
```sh
|
||||
mkdir nightlight
|
||||
cd nightlight
|
||||
touch app.py
|
||||
```
|
||||
|
||||
1. Open this folder in VS Code by selecting *File -> Open...* and selecting the *nightlight* folder, then select **OK**
|
||||
|
||||

|
||||
|
||||
1. Open the `app.py` file from the VS Code explorer and add the following code:
|
||||
|
||||
```python
|
||||
print('Hello World!')
|
||||
```
|
||||
|
||||
The `print` function prints whatever is passed to it to the console.
|
||||
|
||||
1. From the VS Code Terminal, run the following to run your Python app:
|
||||
|
||||
```sh
|
||||
python3 app.py
|
||||
```
|
||||
|
||||
> 💁 You need to explicitly call `python3` to run this code just in case you have Python 2 installed in addition to Python 3 (the latest version). If you have Python2 installed then calling `python` will use Python 2 instead of Python 3
|
||||
|
||||
You should see the following output:
|
||||
|
||||
```output
|
||||
pi@raspberrypi:~/nightlight $ python3 app.py
|
||||
Hello World!
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code/pi](code/pi) folder.
|
||||
|
||||
😀 Your 'Hello World' program was a success!
|
@ -0,0 +1,208 @@
|
||||
# Virtual single-board computer
|
||||
|
||||
Instead of purchasing an IoT device, along with sensors and actuators, you can use your computer to simulate IoT hardware. The [CounterFit project](https://github.com/CounterFit-IoT/CounterFit) allows you to run an app locally that simulates IoT hardware such as sensors and actuators, and access the sensors and actuators from local Python code that is written in the same way as the code you would write on a Raspberry Pi using physical hardware.
|
||||
|
||||
## Setup
|
||||
|
||||
To use CounterFit, you will need to install some free software on your computer.
|
||||
|
||||
### Task
|
||||
|
||||
Install the required software.
|
||||
|
||||
1. Install Python. Refer to the [Python downloads page](https://www.python.org/downloads/) for instructions on install the latest version of Python.
|
||||
|
||||
1. Install Visual Studio Code (VS Code). This is the editor you will be using to write your virtual device code in Python. Refer to the [VS Code documentation](https://code.visualstudio.com?WT.mc_id=academic-17441-jabenn) for instructions on installing VS Code.
|
||||
|
||||
> 💁 You are free to use any Python IDE or editor for these lessons if you have a preferred tool, but the lessons will give instructions based off using VS Code.
|
||||
|
||||
1. Install the VS Code Pylance extension. This is an extension for VS Code that provides Python language support. Refer to the [Pylance extension documentation](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance&WT.mc_id=academic-17441-jabenn) for instructions on installing this extension in VS Code.
|
||||
|
||||
The instructions to install and configure the CounterFit app will be given at the relevant time in the assignment instructions as it is installed on a per-project basis.
|
||||
|
||||
## Hello world
|
||||
|
||||
It is traditional when starting out with a new programming language or technology to create a 'Hello World' application - a small application that outputs something like the text `"Hello World"` to show that all the tools are correctly configured.
|
||||
|
||||
The Hello World app for the virtual IoT hardware will ensure that you have Python and Visual Studio code installed correctly. It will also connect to CounterFit for the virtual IoT sensors and actuators. It won't use any hardware, it will just connect to prove everything is working.
|
||||
|
||||
This app will be in a folder called `nightlight`, and it will be re-used with different code in later parts of this assignment to build the nightlight application.
|
||||
|
||||
### Configure a Python virtual environment
|
||||
|
||||
One of the powerful features of Python is the ability to install [pip packages](https://pypi.org) - these are packages of code written by other people and published to the Internet. You can install a pip package onto your computer with one command, then use that package in your code. You'll be using pip to install a package to talk to CounterFit.
|
||||
|
||||
By default when you install a package it is available everywhere on your computer, and this can lead to problems with package versions - such as one application depending on one version of a package that breaks when you install a new version for a different application. To work around this problem, you can use a [Python virtual environment](https://docs.python.org/3/library/venv.html), essentially a copy of Python in a dedicated folder, and when you install pip packages they get installed just to that folder.
|
||||
|
||||
#### Task
|
||||
|
||||
Configure a Python virtual environment and install the pip packages for CounterFit.
|
||||
|
||||
1. From your terminal or command line, run the following at a location of your choice to create and navigate to a new directory:
|
||||
|
||||
```sh
|
||||
mkdir nightlight
|
||||
cd nightlight
|
||||
```
|
||||
|
||||
1. Now run the following to create a virtual environment in the `.venv` folder
|
||||
|
||||
```sh
|
||||
python3 -m venv .venv
|
||||
```
|
||||
|
||||
> 💁 You need to explicitly call `python3` to create the virtual environment just in case you have Python 2 installed in addition to Python 3 (the latest version). If you have Python2 installed then calling `python` will use Python 2 instead of Python 3
|
||||
|
||||
1. Activate the virtual environment:
|
||||
|
||||
* On Windows run:
|
||||
|
||||
```cmd
|
||||
.venv\Scripts\activate.bat
|
||||
```
|
||||
|
||||
* On macOS or Linux, run:
|
||||
|
||||
```cmd
|
||||
source ./.venv/bin/activate
|
||||
```
|
||||
|
||||
1. Once the virtual environment has been activated, the default `python` command will run the version of Python that was used to create the virtual environment. Run the following to see this:
|
||||
|
||||
```sh
|
||||
python --version
|
||||
```
|
||||
|
||||
You should see the following:
|
||||
|
||||
```output
|
||||
(.venv) ➜ nightlight python --version
|
||||
Python 3.9.1
|
||||
```
|
||||
|
||||
> 💁 Your Python version may be different - as long as it's version 3.6 or higher you are good. If not, delete this folder, install a newer version of Python and try again.
|
||||
|
||||
1. Run the following commands to install the pip packages for CounterFit. These packages include the main CounterFit app as well as shims for Grove hardware. These shims allow you to write code as if you were programming using physical sensors and actuators from the Grove ecosystem, but connected to virtual IoT devices.
|
||||
|
||||
```sh
|
||||
pip install CounterFit
|
||||
pip install counterfit-connection
|
||||
pip install counterfit-shims-grove
|
||||
```
|
||||
|
||||
These pip packages will only be installed in the virtual environment, and will not be available outside of this.
|
||||
|
||||
### Write the code
|
||||
|
||||
Once the Python virtual environment is ready, you can write the code for the 'Hello World' application
|
||||
|
||||
#### Task
|
||||
|
||||
Create a Python application to print `"Hello World"` to the console.
|
||||
|
||||
1. From your terminal or command line, run the following inside the virtual environment to create a Python file called `app.py`:
|
||||
|
||||
* From Windows run:
|
||||
|
||||
```cmd
|
||||
type nul > app.py
|
||||
```
|
||||
|
||||
* On macOS or Linux, run:
|
||||
|
||||
```cmd
|
||||
touch app.py
|
||||
```
|
||||
|
||||
1. Open the current folder in VS Code:
|
||||
|
||||
```sh
|
||||
code .
|
||||
```
|
||||
|
||||
1. When VS Code launches, it will activate the Python virtual environment. You will see this in the bottom status bar:
|
||||
|
||||

|
||||
|
||||
1. If the VS Code Terminal is already running when VS Code starts up, it won't have the virtual environment activated in it. The easiest thing to do is kill the terminal using the **Kill the active terminal instance** button:
|
||||
|
||||

|
||||
|
||||
You can tell if the terminal has the virtual environment activated as the name of the virtual environment will be a prefix on the terminal prompt. For example, it might be:
|
||||
|
||||
```sh
|
||||
(.venv) ➜ nightlight
|
||||
```
|
||||
|
||||
If you don't see `.venv` as a prefix on the prompt, the virtual environment is not active in the terminal.
|
||||
|
||||
1. Launch a new VS Code Terminal by selecting *Terminal -> New Terminal, or pressing `` CTRL+` ``. The new terminal will load the virtual environment, and you will see the call to activate this in the terminal, as well as having the name of the virtual environment (`.venv`) in the prompt:
|
||||
|
||||
```output
|
||||
➜ nightlight source .venv/bin/activate
|
||||
(.venv) ➜ nightlight
|
||||
```
|
||||
|
||||
1. Open the `app.py` file from the VS Code explorer and add the following code:
|
||||
|
||||
```python
|
||||
print('Hello World!')
|
||||
```
|
||||
|
||||
The `print` function prints whatever is passed to it to the console.
|
||||
|
||||
1. From the VS Code terminal, run the following to run your Python app:
|
||||
|
||||
```sh
|
||||
python app.py
|
||||
```
|
||||
|
||||
You should see the following output:
|
||||
|
||||
```output
|
||||
(.venv) ➜ nightlight python app.py
|
||||
Hello World!
|
||||
```
|
||||
|
||||
😀 Your 'Hello World' program was a success!
|
||||
|
||||
### Connect the 'hardware'
|
||||
|
||||
As a second 'Hello World' step, you will run the CounterFit app and connect your code to it. This is the virtual equivalent of plugging in some IoT hardware to a dev kit.
|
||||
|
||||
#### Task
|
||||
|
||||
1. From the VS Code terminal, launch the CounterFit app with the following command:
|
||||
|
||||
```sh
|
||||
CounterFit
|
||||
```
|
||||
|
||||
The app will start running and open in your web browser:
|
||||
|
||||

|
||||
|
||||
You will see it marked as *Disconnected*, with the LED in the top-right corner turned off.
|
||||
|
||||
1. Add the following code to the top of `app.py`:
|
||||
|
||||
```python
|
||||
from counterfit_connection import CounterFitConnection
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
```
|
||||
|
||||
This code imports the `CounterFitConnection` class from the `counterfit_connection` module, which comes from the `counterfit-connection` pip package you installed earlier. It then initializes a connection to the CounterFit app running on `127.0.0.1`, which is an IP address you can always use to access your local computer (often referred to as *localhost*), on port 5000.
|
||||
|
||||
> 💁 If you have other apps running on port 5000, you can change this by updating the port in the code, and running CounterFit using `CounterFit --port <port_number>`, replacing `<port_number>` with the port you want to use.
|
||||
|
||||
1. You will need to launch a new VS Code terminal by selecting the **Create a new integrated terminal** button. This is because the CounterFit app is running in the current terminal.
|
||||
|
||||

|
||||
|
||||
1. In this new terminal, run the `app.py` file as before. You will see the status of CounterFit change to **Connected** and the LED light up.
|
||||
|
||||

|
||||
|
||||
> 💁 You can find this code in the [code/virtual-device](code/virtual-device) folder.
|
||||
|
||||
😀 Your connection to the hardware was a success!
|
@ -0,0 +1,198 @@
|
||||
# Wio Terminal
|
||||
|
||||
The [Wio Terminal from Seeed Studios](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) is an Arduino-compatible microcontroller, with WiFi and some sensors and actuators built in, as well as ports to add more sensors and actuators, using a hardware ecosystem called [Grove](https://www.seeedstudio.com/category/Grove-c-1003.html).
|
||||
|
||||

|
||||
|
||||
## Setup
|
||||
|
||||
To use your Wio Terminal, you will need to install some free software on your computer. You will also need to update the Wio Terminal firmware before you can connect it to WiFi.
|
||||
|
||||
### Task
|
||||
|
||||
Install the required software and update the firmware.
|
||||
|
||||
1. Install Visual Studio Code (VS Code). This is the editor you will be using to write your device code in C/C++. Refer to the [VS Code documentation](https://code.visualstudio.com?WT.mc_id=academic-17441-jabenn) for instructions on installing VS Code.
|
||||
|
||||
> 💁 Another popular IDE for Arduino development is the [Arduino IDE](https://www.arduino.cc/en/software). If you are already familiar with this tool, then you can use it instead of VS Code and PlatformIO, but the lessons will give instructions based off using VS Code.
|
||||
|
||||
1. Install the VS Code PlatformIO extension. This is an extension for VS Code that supports programming microcontrollers in C/C++. Refer to the [PlatformIO extension documentation](https://marketplace.visualstudio.com/items?itemName=platformio.platformio-ide&WT.mc_id=academic-17441-jabenn) for instructions on installing this extension in VS Code. This extension depends on the Microsoft C/C++ extension to work with C and C++ code, and the C/C++ extension is installed automatically when you install PlatformIO.
|
||||
|
||||
1. Connect your Wio Terminal to your computer. The Wio Terminal has a USB-C port on the bottom, and this needs to be connected to a USB port on your computer. The Wio Terminal comes with a USB-C to USB-A cable, but if your computer only has USB-C ports then you will either need a USB-C cable, or a USB-A to USB-C adapter.
|
||||
|
||||
1. Follow the instructions in the [Wio Terminal Wiki WiFi Overview documentation](https://wiki.seeedstudio.com/Wio-Terminal-Network-Overview/) to set up your Wio Terminal and update the firmware.
|
||||
|
||||
## Hello world
|
||||
|
||||
It is traditional when starting out with a new programming language or technology to create a 'Hello World' application - a small application that outputs something like the text `"Hello World"` to show that all the tools are correctly configured.
|
||||
|
||||
The Hello World app for the Wio Terminal will ensure that you have Visual Studio code installed correctly with PlatformIO and set up for microcontroller development.
|
||||
|
||||
### Create a PlatformIO project
|
||||
|
||||
The first step is to create a new project using PlatformIO configured for the Wio Terminal.
|
||||
|
||||
#### Task
|
||||
|
||||
Create the PlatformIO project.
|
||||
|
||||
1. Connect the Wio Terminal to your computer
|
||||
|
||||
1. Launch VS Code
|
||||
|
||||
1. You should see the PlatformIO icon on the side menu bar:
|
||||
|
||||

|
||||
|
||||
Select this menu item, then select *PIO Home -> Open*
|
||||
|
||||

|
||||
|
||||
1. From the welcome screen, select the **+ New Project** button
|
||||
|
||||

|
||||
|
||||
1. Configure the project in the *Project Wizard*:
|
||||
|
||||
1. Name your project `nightlight`
|
||||
|
||||
1. From the *Board* dropdown, type in `WIO` to filter the boards, and select *Seeeduino Wio Terminal*
|
||||
|
||||
1. Leave the *Framework* as *Arduino*
|
||||
|
||||
1. Either leave the *Use default location* checkbox checked, or uncheck it and select a location for your project
|
||||
|
||||
1. Select the **Finish** button
|
||||
|
||||

|
||||
|
||||
PlatformIO will download the components it needs to compile code for the Wio Terminal and create your project. This may take a few minutes.
|
||||
|
||||
### Investigate the PlatformIO project
|
||||
|
||||
The VS Code explorer will show a number of files and folders created by the PlatformIO wizard.
|
||||
|
||||
#### Folders
|
||||
|
||||
* `.pio` - this folder contains temporary data needed by PlatformIO such as libraries or compiled code. It is recreated automatically if deleted, and you don't need to add this to source code control if you are sharing your project on sites such as GitHub.
|
||||
* `.vscode` - this folder contains configuration used by PlatformIO and VS Code. It is recreated automatically if deleted, and you don't need to add this to source code control if you are sharing your project on sites such as GitHub.
|
||||
* `include` - this folder is for external header files needed when adding additional libraries to your code. You won't be using this folder in any of these lessons.
|
||||
* `lib` - this folder is for external libraries that you want to call from your code. You won't be using this folder in any of these lessons.
|
||||
* `src` - this folder contains the main source code for your application. Initially it will contain a single file - `main.cpp`.
|
||||
* `test` - this folder is where you would put any unit tests for your code
|
||||
|
||||
#### Files
|
||||
|
||||
* `main.cpp` - this file in the `src` folder contains the entry point for your application. If you open the file, you will see the following:
|
||||
|
||||
```cpp
|
||||
#include <Arduino.h>
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
}
|
||||
```
|
||||
|
||||
When the device starts up, the Arduino framework will run the `setup` function once, then run the `loop` function repeatedly until the device is turned off.
|
||||
|
||||
* `.gitignore` - this file lists the files an directories to be ignored when adding your code to git source code control, such as uploading to a repository on GitHub.
|
||||
|
||||
* `platformio.ini` - this file contains configuration for your device and app. If you open this file, you will see the following:
|
||||
|
||||
```ini
|
||||
[env:seeed_wio_terminal]
|
||||
platform = atmelsam
|
||||
board = seeed_wio_terminal
|
||||
framework = arduino
|
||||
```
|
||||
|
||||
The `[env:seeed_wio_terminal]` section has configuration for the Wio Terminal. You can have multiple `env` sections so your code can be compiled for multiple boards.
|
||||
|
||||
The other values match the configuration from the project wizard:
|
||||
|
||||
* `platform = atmelsam` defines the hardware that the Wio Terminal uses (an ATSAMD51-based microcontroller)
|
||||
* `board = seeed_wio_terminal` defines the type of microcontroller board (the Wio Terminal)
|
||||
* `framework = arduino` defines that this project is using the Arduino framework.
|
||||
|
||||
### Write the Hello World app
|
||||
|
||||
You're now ready to write the Hello World app.
|
||||
|
||||
#### Task
|
||||
|
||||
Write the Hello World app.
|
||||
|
||||
1. Open the `main.cpp` file in VS Code
|
||||
|
||||
1. Change the code to match the following:
|
||||
|
||||
```cpp
|
||||
#include <Arduino.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
while (!Serial)
|
||||
; // Wait for Serial to be ready
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println("Hello World");
|
||||
delay(5000);
|
||||
}
|
||||
```
|
||||
|
||||
The `setup` function initializes a connection to the serial port - in this case the USB port that is used to connect the Wio Terminal to your computer. The parameter `9600` is the [baud rate](https://wikipedia.org/wiki/Symbol_rate) (also known as Symbol rate), or speed that data will be sent over the serial port in bits per second. This setting means 9,600 bits (0s and 1s) of data are sent each second. It then waits for the serial port to be ready.
|
||||
|
||||
The `loop` function sends the line `Hello World!` to the serial port, so the characters of `Hello World!` along with a new line character. It then sleeps for 5,000 milliseconds, or 5 seconds. After the `loop` ends, it is run again, and again, and so on all the time the microcontroller is powered on.
|
||||
|
||||
1. Build and upload the code to the Wio Terminal
|
||||
|
||||
1. Open the VS Code command palette
|
||||
|
||||
1. Type `PlatformIO Upload` to search for the upload option, and select *PlatformIO: Upload*
|
||||
|
||||

|
||||
|
||||
PlatformIO will automatically build the code if needed before uploading.
|
||||
|
||||
1. The code will be compiled, and uploaded to the Wio Terminal
|
||||
|
||||
> 💁 If you are using macOS you will see a notification about a *DISK NOT EJECTED PROPERLY*. This is because the Wio Terminal gets mounted as a drive as part of the flashing process, and it is disconnected when the compiled code is written to the device. You can ignore this notification.
|
||||
|
||||
⚠️ If you get errors about the upload port being unavailable, first make sure you have the Wio Terminal connected to your computer, and switched on using the switch on the left hand side of the screen. The green light on the bottom should be on. If you still get the error, pull the on/off switch down twice in quick succession to force the Wio Terminal into bootloader mode and try the upload again.
|
||||
|
||||
PlatformIO has a Serial Monitor that can monitor data sent over the USB cable from the Wio Terminal. This allows you to monitor the data sent by the `Serial.println("Hello World");` command.
|
||||
|
||||
1. Open the VS Code command palette
|
||||
|
||||
1. Type `PlatformIO Serial` to search for the Serial Monitor option, and select *PlatformIO: Serial Monitor*
|
||||
|
||||

|
||||
|
||||
A new terminal will open, and the data sent over the serial port will be streamed into this terminal:
|
||||
|
||||
```output
|
||||
> Executing task: platformio device monitor <
|
||||
|
||||
--- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
|
||||
--- More details at http://bit.ly/pio-monitor-filters
|
||||
--- Miniterm on /dev/cu.usbmodem101 9600,8,N,1 ---
|
||||
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
|
||||
Hello World
|
||||
Hello World
|
||||
```
|
||||
|
||||
You will see `Hello World` appear every 5 seconds.
|
||||
|
||||
> 💁 You can find this code in the [code/wio-terminal](code/wio-terminal) folder.
|
||||
|
||||
😀 Your 'Hello World' program was a success!
|
@ -0,0 +1,269 @@
|
||||
# A deeper dive into IoT
|
||||
|
||||
Add a sketchnote if possible/appropriate
|
||||
|
||||

|
||||
|
||||
## Pre-lecture quiz
|
||||
|
||||
[Pre-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/3)
|
||||
|
||||
## Introduction
|
||||
|
||||
This lesson dives deeper into some of the concepts covered in the last lesson.
|
||||
|
||||
In this lesson we'll cover:
|
||||
|
||||
* [Components of an IoT application](#components-of-an-iot-application)
|
||||
* [Deeper dive into microcontrollers](#deeper-dive-into-microcontrollers)
|
||||
* [Deeper dive into single-board computers](#deeper-dive-into-single-board-computers)
|
||||
|
||||
## Components of an IoT application
|
||||
|
||||
The two components of an IoT application are the *Internet* and the *thing*. Lets look at these two components in a bit more detail.
|
||||
|
||||
### The Thing
|
||||
|
||||

|
||||
|
||||
***Raspberry Pi 4. Michael Henzler / [Wikimedia Commons](https://commons.wikimedia.org/wiki/Main_Page) / [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)***
|
||||
|
||||
The **Thing** part of IoT refers to a device that can interact with the physical world. These devices are usually small, low-priced computers, running at low speeds and using low power - for example simple microcontrollers with kilobytes of RAM (as opposed to gigabytes in a PC) running at only a few hundred megahertz (as opposed to gigahertz in a PC), but consuming sometimes so little power they can run for weeks, months or even years on batteries.
|
||||
|
||||
These devices interact with the physical world, either by using sensors to gather data from their surroundings, or by controlling outputs or actuators to make physical changes. The typical example of this is a smart thermostat - a device that has a temperature sensor, a means to set a desired temperature such as a dial or touchscreen, and a connection to a heating or cooling system that can be turned on when the temperature detected is outside the desired range. The temperature sensor detects that the room is too cold and an actuator turns the heating on.
|
||||
|
||||

|
||||
|
||||
***A simple thermostat. Temperature by Vectors Market / Microcontroller by Template / dial by Jamie Dickinson / heater by Pascal Heß - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
There are a huge range of different things that can act as IoT devices, from dedicated hardware that senses one thing, to general purpose devices, even your smartphone! A smartphone can use sensors to detect the world around it, and actuators to interact with the world - for example using a GPS sensor to detect your location and a speaker to give you navigation instructions to a destination.
|
||||
|
||||
✅ Think of other systems you have around you that read data from a sensor and use that to make decisions. One example would be the thermostat on an oven. Can you find more?
|
||||
|
||||
### The Internet
|
||||
|
||||
The **Internet** side of an IoT application consists of applications that the IoT device can connect to to send and receive data, as well as other applications that can process the data from the IoT device and help make decisions on what requests to send to the IoT devices actuators.
|
||||
|
||||
One typical setup would be having some kind of cloud service that the IoT device connects to, and this cloud service handles things like security, as well as receiving messages from the IoT device, and sending messages back to the device. This cloud service would then connect to other applications that can process or store sensor data, or use the sensor data with data from other systems to make decisions.
|
||||
|
||||
Devices also don't always connect directly to the Internet themselves via WiFi or wired connections. Some devices use mesh networking to talk to each other over technologies such as bluetooth, connecting via a hub device that has the Internet connection.
|
||||
|
||||
With the example of a smart thermostat, the thermostat would connect using home WiFi to a cloud service running in the cloud. It would send the temperature data to this cloud service, and from there it will be written to a database of some kind allowing the homeowner to check the current and past temperatures using a phone app. Another service in the cloud would know what temperature the homeowner wants, and send messages back to the IoT device via the cloud service to tell the heating system to turn on or off.
|
||||
|
||||

|
||||
|
||||
***An Internet connected thermostat with mobile app control. Temperature by Vectors Market / Microcontroller by Template / dial by Jamie Dickinson / heater by Pascal Heß / mobile phone by Alice-vector / Cloud by Debi Alpa Nugraha - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
An even smarter version could use AI in the cloud with data from other sensors connected to other IoT devices such as occupancy sensors that detect what rooms are in use, as well as data such as weather and even your calendar, to make decisions on how to set the temperature in a smart fashion. For example it could turn your heating off if it reads from your calendar you are on vacation, or turn off the heating on a room by room basis depending on what rooms you use, learning from the data to be more and more accurate over time.
|
||||
|
||||

|
||||
|
||||
***An Internet connected thermostat using multiple room sensors, with mobile app control, as well as intelligence from weather and calendar data. Temperature by Vectors Market / Microcontroller by Template / dial by Jamie Dickinson / heater by Pascal Heß / mobile phone and Calendar by Alice-vector / Cloud by Debi Alpa Nugraha / smart sensor by Andrei Yushchenko / weather by Adrien Coquet - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
✅ What other data could help make an Internet connected thermostat smarter?
|
||||
|
||||
### IoT on the Edge
|
||||
|
||||
Although the I in IoT stands for Internet, these devices don't have to connect to the Internet. In some cases devices can connect to 'edge' devices - gateway devices that run on your local network meaning you can process data without making a call over the Internet. This can be faster when you have a lot of data or a slow Internet connection, it allows you to run offline where Internet connectivity is not possible such as on a ship or in a disaster area when responding to a humanitarian crisis, and allows you to keep data private. Some devices will contain processing code created using cloud tools, and run this locally to gather and respond to data without using an Internet connection to make a decision.
|
||||
|
||||
One example of this is a smart home device such as an Apple HomePod, Amazon Alexa, or Google Home, which will listen to your voice using AI models trained in the cloud, and will 'wake up' when a certain word or phrase is spoken, and only then send your speech to the Internet for processing, keeping everything else you say private.
|
||||
|
||||
✅ Think of other scenarios where privacy is important so processing of data would be better done on the edge rather than in the cloud. As a hint - think about IoT devices with cameras or other imaging devices on them.
|
||||
|
||||
### IoT Security
|
||||
|
||||
With any Internet connection, security is an important consideration. There is an old joke that 'the S in IoT stands for Security' - there is no 'S' in IoT, implying it is not secure.
|
||||
|
||||
IoT devices connect to a cloud service, and therefore are only as secure as that cloud service - if your cloud service allows any device to connect then malicious data can be sent, or virus attacks can take place. This can have very real world consequences as IoT devices interact and control other devices. For example, the [Stuxnet worm](https://wikipedia.org/wiki/Stuxnet) manipulated valves in centrifuges to damage them. Hackers have also taken advantage of [poor security to access baby monitors](https://www.npr.org/sections/thetwo-way/2018/06/05/617196788/s-c-mom-says-baby-monitor-was-hacked-experts-say-many-devices-are-vulnerable) and other home surveillance devices.
|
||||
|
||||
> 💁 Sometimes IoT devices and the edge devices run on network completely isolated from the Internet to keep the data private and secure. This is know as [air-gapping](https://wikipedia.org/wiki/Air_gap_(networking)).
|
||||
|
||||
## Deeper dive into microcontrollers
|
||||
|
||||
In the last lesson we introduced microcontrollers. Lets now look deeper into them.
|
||||
|
||||
### CPU
|
||||
|
||||
The CPU is the 'brain' of the microcontroller. It is the processor that runs your code and can send data to and receive data from any connected devices. CPUs can contain one or more cores - essentially one or more CPUs that can work together to run your code.
|
||||
|
||||
CPUs rely on a clock to tick many millions or billions of times a second. Each tick, or cycle, synchronizes the actions that the CPU can take. With each tick, the CPU can execute an instruction from a program, such as to retrieve data from an external device, or perform a mathematical calculation. This regular cycle allows for all actions to be completed before the next instructions is processed.
|
||||
|
||||
The faster the clock cycle, the more instructions that can be processed each second, and therefore the faster the CPU. CPU speeds are measured in [Hertz (Hz)](https://wikipedia.org/wiki/Hertz), a standard unit where 1 Hz means one cycle or clock tick per second.
|
||||
|
||||
> 🎓 CPU speeds are often given in MHz or GHz. 1MHz is 1 million Hz, 1GHz is 1 billion Hz.
|
||||
|
||||
> 💁 CPUs execute programs using the [fetch-decode-execute cycle](https://wikipedia.org/wiki/Instruction_cycle). Every clock tick the CPU will fetch the next instruction from memory, decode it, then execute it such as using an arithmetic logic unit (ALU) to add 2 numbers. Some executions will take multiple ticks to run, so the next cycle will run at the next tick after the instruction has completed.
|
||||
|
||||

|
||||
|
||||
***CPU by Icon Lauk / ram by Atif Arshad - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
Microcontrollers have much lower clock speeds than desktop or laptop computers, or even most smartphones. The Wio Terminal for example has a CPU that runs at 120MHz, or 120,000,000 cycles per second.
|
||||
|
||||
✅ An average PC or Mac has a CPU with multiple cores running at multiple GigaHertz, meaning the clock ticks billions of times a second. Research the clock speed of your computer and see how many times faster it is than the Wio terminal.
|
||||
|
||||
Each clock cycle draws power and generates heat. The faster the ticks, the more power consumed and more heat created. PC's have heat sinks and fans to remove heat, without which they would overheat and shut down within seconds. Microcontrollers often have neither as they run much cooler and therefore much slower. PC's run off mains power or large batteries for a few hours, microcontrollers can run for days, months, or even years off small batteries. Microcontrollers can also have cores that run at different speeds, switching to slower lower power cores when the demand on the CPU is low to reduce power consumption.
|
||||
|
||||
> 💁 Some PCs and Macs are adopting the same mix of fast high power cores and slower low power cores, switching to save battery. For example the M1 chip in the latest Apple laptops can switch between 4 performance cores and 4 efficiency cores to optimize battery life or speed depending on the task being run.
|
||||
|
||||
✅ Do a little research: Read up on CPUs on the [Wikipedia CPU article](https://wikipedia.org/wiki/Central_processing_unit)
|
||||
|
||||
#### Task
|
||||
|
||||
Investigate the Wio Terminal.
|
||||
|
||||
If you are using a Wio Terminal for these lessons, see if you can find the CPU. Find the *Hardware Overview* section of the [Wio Terminal product page](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) for a picture of the internals, and see if you can see the CPU through the clear plastic window on the back.
|
||||
|
||||
### Memory
|
||||
|
||||
Microcontrollers usually have two types of memory - program memory and random-access memory (RAM).
|
||||
|
||||
Program memory is non-volatile, which means whatever is written to it stays when there is no power to the device. This is the memory that stores your program code.
|
||||
|
||||
RAM is the memory used by the program to run, containing variables allocated by your program and data gathered from peripherals. RAM is volatile, when the power goes out the contents is lost, effectively resetting your program.
|
||||
|
||||
> 🎓 Program memory stores your code and stays when there is no power.
|
||||
|
||||
> 🎓 RAM is used to run your program, and is reset when there is no power
|
||||
|
||||
Like with the CPU, the memory on a microcontroller is orders of magnitude smaller than a PC or Mac. A typical PC might have 8 Gigabytes (GB) of RAM, or 8,000,0000,000 bytes, with each byte enough space to store a single letter or a number from 0-255. A microcontroller would have only Kilobytes (KB) of RAM, with a kilobyte being 1,000 bytes. The Wio terminal mentioned above has 192KB of RAM, or 192,000 bytes - more than 40,000 times less than an average PC!
|
||||
|
||||
The diagram below shows the relative size difference between 192KB and 8GB - the small dot in the center represents 192KB.
|
||||
|
||||

|
||||
|
||||
Program storage is also smaller than a PC. A typical PC might have a 500GB hard drive for program storage, whereas a microcontroller might have only kilobytes or maybe a few megabytes (MB) of storage (1MB is 1,000KB, or 1,000,000 bytes). The Wio terminal has 4MB of program storage.
|
||||
|
||||
✅ Do a little research: How much RAM and storage does the computer you are using to read this have? How does this compare to a microcontroller?
|
||||
|
||||
### Input/Output
|
||||
|
||||
Microcontrollers need input and output (I/O) connections to read data from sensors and send control signals to actuators. They usually contain a number of general-purpose input/output (GPIO) pins. These pins can be configured in software to be input (that is they receive a signal), or output (they send a signal).
|
||||
|
||||
🧠⬅️ Input pins are used to read values from sensors
|
||||
|
||||
🧠➡️ Output pins send instructions to actuators
|
||||
|
||||
✅ You'll learn more about this in a subsequent lesson.
|
||||
|
||||
#### Task
|
||||
|
||||
Investigate the Wio Terminal.
|
||||
|
||||
If you are using a Wio Terminal for these lessons, find the GPIO pins. Find the *Pinout diagram* section of the [Wio Terminal product page](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) to see which pins are which. The Wio Terminal comes with a sticker you can mount on the back with pin numbers, so add this now if you haven't already.
|
||||
|
||||
### Physical size
|
||||
|
||||
Microcontrollers are typically small in size, with the smallest, a [Freescale Kinetis KL03 MCU is small enough to fit in the dimple of a golf ball](https://www.edn.com/tiny-arm-cortex-m0-based-mcu-shrinks-package/). Just the CPU in a PC can measure 40mm x 40mm, and that's not including the heat sinks and fans needed to ensure the CPU can run for more than a few seconds without overheating, substantially larger than a complete microcontroller. The Wio terminal developer kit with a microcontroller, case, screen and a range of connections and components isn't much bigger than a bare Intel i9 CPU, and substantially smaller than the CPU with a heat sink and fan!
|
||||
|
||||
| Device | Size |
|
||||
| ------------------------------- | --------------------- |
|
||||
| Freescale Kinetis KL03 | 1.6mm x 2mm x 1mm |
|
||||
| Wio terminal | 72mm x 57mm x 12mm |
|
||||
| Intel i9 CPU, Heat sink and fan | 136mm x 145mm x 103mm |
|
||||
|
||||
### Frameworks and operating systems
|
||||
|
||||
Due to their low speed and memory size, microcontrollers don't run an operating system (OS) in the desktop sense of the word. The operating system that makes your computer run (Windows, Linux or macOS) needs a lot of memory and processing power to run tasks that are completely unnecessary for a microcontroller. Remember that microcontrollers are usually programmed to perform one or more very specific tasks, unlike a general purpose computer like a PC or Mac that needs to support a user interface, play music or movies, provide tools to write documents or code, play games, or browse the Internet.
|
||||
|
||||
To program a microcontroller without an OS you do need some tooling to allow you to build your code in a way that the microcontroller can run, using APIs that can talk to any peripherals. Each microcontroller is different, so manufacturers normally support standard frameworks which allow you to follow a standard 'recipe' to build your code and have it run on any microcontroller that supports that framework.
|
||||
|
||||
You can program microcontrollers using an OS - often referred to as a real-time operating system (RTOS), as these are designed to handle sending data to and from peripherals in real time. These operating systems are very lightweight and provide features such as:
|
||||
|
||||
* Multi-threading, allowing your code to run more than one block of code at the same time, either on multiple cores or by taking turns on one core
|
||||
* Networking to allow communicating over the Internet securely
|
||||
* Graphical user interface (GUI) components for building user interfaces (UI) on devices that have screens.
|
||||
|
||||
✅ Read up on some different RTOSes: [Azure RTOS](https://azure.microsoft.com/services/rtos/?WT.mc_id=academic-17441-jabenn), [FreeRTOS](https://www.freertos.org), [Zephyr](https://www.zephyrproject.org)
|
||||
|
||||
#### Arduino
|
||||
|
||||

|
||||
|
||||
[Arduino](https://www.arduino.cc) is probably the most popular microcontroller framework, especially among students, hobbyists and makers. Arduino is an open source electronics platform combining software and hardware. You can buy and Arduino compatible boards from Arduino themselves, or from other manufacturers, then code using the Arduino framework.
|
||||
|
||||
Arduino boards are coded in C or C++. Using C/C++ allows your code to be compiled very small and run fast, something needed on a constrained device such as a microcontroller. The core of an Arduino application is referred to as a sketch, and is C/C++ code with 2 functions - `setup` and `loop`. When the board starts up, the Arduino framework code will run the `setup` function once, then it will run the `loop` function again and again, running it continuously until the power is powered off.
|
||||
|
||||
You would write your setup code in the `setup` function, such as connecting to WiFi and cloud services or initializing pins for input and output. Your loop code would then contain processing code, such as reading from a sensor and sending the value to the cloud. You would normally include a delay in each loop, for example if you only want sensor data to be sent every 10 seconds you would add a delay of 10 seconds at the end of the loop so the microcontroller can sleep, saving power, then run the loop again when needed 10 seconds later.
|
||||
|
||||

|
||||
|
||||
✅ This program architecture is know as an *event loop* or *message loop*. Many applications use this under the hood, and is the standard for most desktop applications that run on OSes like Windows, macOS or Linux. The `loop` listens for messages from user interface components such as buttons, or devices like the keyboard, and responds to them. You can read more in this [article on the event loop](https://wikipedia.org/wiki/Event_loop).
|
||||
|
||||
Arduino provides standard libraries for interacting with microcontrollers and the I/O pins, with different implementations under the hood to run on different microcontrollers. For example, the [`delay` function](https://www.arduino.cc/reference/en/language/functions/time/delay/) will pause the program for a given period of time, the [`digitalRead` function](https://www.arduino.cc/reference/en/language/functions/digital-io/digitalread/) will read a value of `HIGH` or `LOW` from the given pin, regardless of which board the code is run on. These standard libraries mean that Arduino code written for one board can be recompiled for any other Arduino board and will run, assuming that the pins are the same and the boards support the same features.
|
||||
|
||||
There is a large ecosystem of third-party Arduino libraries that allow you to add extra features to your Arduino projects, such as using sensors and actuators, or connecting to cloud IoT services.
|
||||
|
||||
##### Task
|
||||
|
||||
Investigate the Wio Terminal.
|
||||
|
||||
If you are using a Wio Terminal for these lessons, re-read the code you wrote in the last lesson. Find the `setup` and `loop` function. Monitor the serial output to see the loop function being called repeatedly. Try adding code to the `setup` function to write to the serial port and see this code is only called once each time you reboot. Try rebooting your device with the power switch on the side to see this called each time the device reboots.
|
||||
|
||||
## Deeper dive into single-board computers
|
||||
|
||||
In the last lesson we introduced single-board computers. Lets now look deeper into them.
|
||||
|
||||
### Raspberry Pi
|
||||
|
||||

|
||||
|
||||
The [Raspberry Pi Foundation](https://www.raspberrypi.org) is a charity from the UK founded in 2009 to promote the study of computer science, especially at school level. As part of this mission they developed a single-board computer, called the Raspberry Pi. Raspberry Pis are currently available in 3 variants - a full size version, the smaller Pi Zero, and an compute module that can be built into your final IoT device.
|
||||
|
||||

|
||||
|
||||
***Raspberry Pi 4. Michael Henzler / [Wikimedia Commons](https://commons.wikimedia.org/wiki/Main_Page) / [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)***
|
||||
|
||||
The latest iteration of the full size Raspberry Pi is the Raspberry Pi 4B. This has a quad-core (4 core) CPU running at 1.5GHz, 2, 4, or 8GB of RAM, gigabit ethernet, WiFi, 2 HDMI ports supporting 4k screens, an audio and composite video output port, USB ports (2 USB 2.0, 2 USB 3.0), 40 GPIO pins, a camera connector for a Raspberry Pi camera module, and an SD card slot. All this on a board that is 88mm x 58mm x 19.5mm and is powered by a 3A USB-C power supply. These start at US$35, much cheaper than a PC or Mac.
|
||||
|
||||
> 💁 There is also a Pi400 all in one computer with a Pi4 built into a keyboard.
|
||||
|
||||

|
||||
|
||||
The Pi Zero is much smaller, with lower power. It has a single core 1GHz CPU, 512MB of RAM, WiFi (in the Zero W model), a single HDMI port, a micro-USB port, 40 GPIO pins, a camera connector for a Raspberry Pi camera module, and an SD card slot. It measures 65mm x 30mm x 5mm, and draws very little power. The Zero is US$5, with the W version with WiFi US$10.
|
||||
|
||||
> 🎓 The CPUs in both of these are ARM processors, as opposed to the Intel/AMD x86 or x64 processors you find in most PCs and Macs. These are similar to the CPUs you find in some microcontrollers, as well as nearly all mobile phones, the Microsoft Surface X, and the new Apple Silicon based Apple Macs.
|
||||
|
||||
All variants of the Raspberry Pi run a version of Debian Linux called Raspberry Pi OS. This is available as a lite version with no desktop, which is perfect for 'headless' projects where you don't need a screen, or a full version with a full desktop environment, with web browser, office applications, coding tools and games. As the OS is a version of Debian Linux, you can install any application or tool that runs on Debian and is built for the ARM processor inside the Pi.
|
||||
|
||||
#### Task
|
||||
|
||||
Investigate the Raspberry Pi.
|
||||
|
||||
If you are using a Raspberry Pi for these lessons, read up about the different hardware components on the board.
|
||||
|
||||
* You can find details on the processors used on the [Raspberry Pi hardware documentation page](https://www.raspberrypi.org/documentation/hardware/raspberrypi/). Read up on the processor used in the Pi you are using.
|
||||
* Locate the GPIO pins. Read more about them on the [Raspberry Pi GPIO documentation](https://www.raspberrypi.org/documentation/hardware/raspberrypi/gpio/README.md). Use the [GPIO Pin Usage guide](https://www.raspberrypi.org/documentation/usage/gpio/README.md) to identify the different pins on your Pi.
|
||||
|
||||
### Programming single-board computers
|
||||
|
||||
Single-board computers are full computers, running a full OS. This means there is a wide range of programming languages, frameworks and tools you can use to code them, unlike microcontrollers which rely on support for the board in frameworks like Arduino. Most programming languages have libraries that can access the GPIO pins to send and receive data from sensors and actuators.
|
||||
|
||||
✅ What programming languages are you familiar with? Are they supported on Linux?
|
||||
|
||||
The most common programming language for building IoT applications on a Raspberry Pi is Python. There is a huge ecosystem of hardware designed for the Pi, and nearly all of these include the relevant code needed to use them as Python libraries. Some of these ecosystems are based off 'hats' - so called because they sit on top of the Pi like a hat and connect with a large socket to the 40 GPIO pins. These hats provide additional capabilities, such as screens, sensors, remote controlled cars, or adapters to allow you to plug in sensors with standardized cables
|
||||
|
||||
### Use of single-board computers in professional IoT deployments
|
||||
|
||||
Single-board computers are used for professional IoT deployments, not just as developer kits. They can provide a powerful way to control hardware and run complex tasks such as running machine learning models. For example, there is a [Raspberry Pi 4 compute module](https://www.raspberrypi.org/blog/raspberry-pi-compute-module-4/) that provides all the power of a Raspberry Pi 4 but in a compact and cheaper form factor without most of the ports, designed to be installed into custom hardware.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Challenge
|
||||
|
||||
The challenge in the last lesson was to list as many IoT devices as you can that are in your home, school or workplace. For every device in this list, do you think they are built around microcontrollers or single-board computers, or even a mixture of both?
|
||||
|
||||
## Post-lecture quiz
|
||||
|
||||
[Post-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/4)
|
||||
|
||||
## Review & Self Study
|
||||
|
||||
* Read the [Arduino getting started guide](https://www.arduino.cc/en/Guide/Introduction) to understand more about the Arduino platform.
|
||||
* Read the [introduction to the Raspberry Pi 4](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/) to learn more about Raspberry Pis.
|
||||
|
||||
✅ Use these guides, along with the costs shown by following the links in the [hardware guide](../../hardware.md) to decide on what hardware platform you want to use, or if you would rather use a virtual device.
|
||||
|
||||
## Assignment
|
||||
|
||||
[Compare and contrast microcontrollers and single-board computers](assignment.md)
|
@ -0,0 +1,12 @@
|
||||
# Compare and contrast microcontrollers and single-board computers
|
||||
|
||||
## Instructions
|
||||
|
||||
This lesson covered microcontrollers and single-board computers. Create a table comparing and contrasting them, and note at least 2 reasons why you would use a microcontroller over a single-board computer, and at least 2 reasons why you would use a single-board computer over a microcontroller.
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| Create a table comparing microcontrollers to single-board computers | Created a list with multiple items correctly comparing and contrasting | Created a list with only a couple of items | Was only able to come up with one item, or no items to compare and contrast |
|
||||
| Reasons for using one over the other | Was able to provide 2 or more reasons for microcontrollers, and 2 or more for single-board computers | Was only able to provide 1-2 reasons for a microcontroller, and 1-2 reasons for a single-board computer | Was unable to provide 1 or more reasons for a microcontroller or for a single-board computer |
|
@ -0,0 +1,224 @@
|
||||
# Interact with the physical world with sensors and actuators
|
||||
|
||||
Add a sketchnote if possible/appropriate
|
||||
|
||||

|
||||
|
||||
## Pre-lecture quiz
|
||||
|
||||
[Pre-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/5)
|
||||
|
||||
## Introduction
|
||||
|
||||
This lesson introduces two of the important concepts for your IoT device - sensors and actuators. You will also get hands on with them both, adding a light sensor to your IoT project, then adding an LED controlled by light levels, effectively building a nightlight.
|
||||
|
||||
In this lesson we'll cover:
|
||||
|
||||
* [What are sensors?](#what-are-sensors)
|
||||
* [Use a sensor](#use-a-sensor)
|
||||
* [Sensor types](#sensor-types)
|
||||
* [What are actuators?](#what-are-actuators)
|
||||
* [Use an actuator](#use-an-actuator)
|
||||
* [Actuator types](#actuator-types)
|
||||
|
||||
## What are sensors?
|
||||
|
||||
Sensors are hardware devices that sense the physical world - that is they measure one or more properties around them and send the information to an IoT device. Sensors cover a huge range of devices as there are so many things that can be measured, from natural properties such as air temperature to physical interactions such as movement.
|
||||
|
||||
Some common sensors include:
|
||||
|
||||
* Temperature sensors - these sense the air temperature, or the temperature of what they are immersed in. For hobbyists and developer, these are often combined with air pressure and humidity in a single sensor.
|
||||
* Buttons - they sense when they have been pressed
|
||||
* Light sensors - these detect light levels, and can be for specific colors, UV light, IR light, or general visible light
|
||||
* Cameras - these sense a visual representation of the world by taking a photograph or streaming video
|
||||
* Accelerometers - these sense movement in multiple directions
|
||||
* Microphones - these sense sound, either general sound levels, or directional sound
|
||||
|
||||
✅ Do some research. What sensors does your phone have?
|
||||
|
||||
All sensors have one thing in common - the convert whatever they sense into an electrical signal that can be interpreted by an IoT device. How this electrical signal is interpreted depends on the sensor, as well as the communication protocol used to communicate with the IoT device.
|
||||
|
||||
## Use a sensor
|
||||
|
||||
Follow the relevant guide below to add a sensor to your IoT device:
|
||||
|
||||
* [Arduino - Wio Terminal](wio-terminal-sensor.md)
|
||||
* [Single-board computer - Raspberry Pi](pi-sensor.md)
|
||||
* [Single-board computer - Virtual device](virtual-device-sensor.md)
|
||||
|
||||
## Sensor types
|
||||
|
||||
Sensors are either analog or digital.
|
||||
|
||||
### Analog sensors
|
||||
|
||||
Some of the most basic sensors are analog sensors. These sensors receive a voltage from the IoT device, the sensor components adjust this voltage, and the voltage that is returned from the sensor is measured to give the sensor value.
|
||||
|
||||
> 🎓 Voltage is a measure of how mush push there is to move electricity from one place to another, such as from a positive terminal of a battery to the negative terminal. For example, a standard AA battery is 1.5V (V is the symbol for volts), and can push electricity with the force of 1.5V from it's positive terminal to its negative terminal. Different electrical hardware requires different voltages to work, for example an LED can light with between 2-3V, but a 100W filament lightbulb would need 240V. You can read more about voltage on the [Voltage page on Wikipedia](https://wikipedia.org/wiki/Voltage).
|
||||
|
||||
One example of this is a potentiometer. This is a dial that you can rotate between two positions and the sensor measures the rotation.
|
||||
|
||||

|
||||
|
||||
***A potentiometer. Microcontroller by Template / dial by Jamie Dickinson - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
The IoT device will send an electrical signal to the potentiometer at a voltage, such as 5 volts (5V). As the potentiometer is adjusted it changes the voltage that comes out the other side. Imagine you have a potentiometer labelled as a dial that goes from 0 to [11](https://wikipedia.org/wiki/Up_to_eleven), such as a volume knob on an amplifier. When the potentiometer is in the full off position (0) then 0v (0 volts) will come out. When it is in the full on position (11), 5V (5 volts) will come out.
|
||||
|
||||
> 🎓 This is an oversimplification, and you can read more on potentiometers and variable resistors on the [potentiometer Wikipedia page](https://wikipedia.org/wiki/Potentiometer).
|
||||
|
||||
The voltage that comes out the sensor is then read by the IoT device, and the device can respond to it. Depending on the sensor, this voltage can be an arbitrary value, or can map to a standard unit. For example an analog temperature sensor based on a [thermistor](https://wikipedia.org/wiki/Thermistor) changes it's resistance depending on the temperature. The output voltage can then be converted to a temperature in Kelvin, and correspondingly into °C or °F, by calculations in code.
|
||||
|
||||
✅ What do you think happens if the sensor returns a higher voltage than was sent (for example coming from an external power supply)? ⛔️ DO NOT test this out.
|
||||
|
||||
#### Analog to digital conversion
|
||||
|
||||
IoT devices are digital - they can't work with analog values, they only work with 0s and 1s. This means that analog sensor values need to be converted to a digital signal before they can be processed. Many IoT devices have analog-to-digital converters (ADCs) to convert analog inputs to digital representations of their value. Sensors can also work with ADCs via a connector board. For example, in the Seeed Grove ecosystem with a Raspberry Pi, analog sensors connect to specific ports on a 'hat' that sits on the Pi connected to the Pis GPIO pins, and this hat has an ADC to convert the voltage into a digital signal that can be sent of the Pi's GPIO pins.
|
||||
|
||||
Imagine you have an analog light sensor connected to an IoT device that uses 3.3V, and is returning a value of 1v. This 1v doesn't mean anything in the digital world, so needs to be converted. The voltage will be converted to an analog value using a scale depending on the device and sensor. One example is the Seeed Grove light sensor which outputs values from 0 to 1,023. For this sensor running at 3.3V, a 1v output would be a value of 300. An IoT device can't handle 300 as an analog value, so the value would be converted to `0000000100101100`, the binary representation of 300 by the Grove hat. This would then be processed by the IoT device.
|
||||
|
||||
✅ If you don't know binary then do a small amount of research to learn how numbers are represented by 0s and 1s. The [BBC Bitesize introduction to binary lesson](https://www.bbc.co.uk/bitesize/guides/zwsbwmn/revision/1) is a great place to start.
|
||||
|
||||
From a coding perspective, all this is usually handled by libraries that come with the sensors, so you don't need to worry about this conversion yourself. For the Grove light sensor you would use the Python library and call the `light` property, or use the Arduino library and call `analogRead` to get a value of 300.
|
||||
|
||||
### Digital sensors
|
||||
|
||||
Digital sensors, like analog sensors, detect the world around them using changes in electrical voltage. The difference is they output a digital signal, either by only measuring two states, or by using a built-in ADC. Digital sensors are becoming more and more common to avoid the need to use an ADC either in a connector board or on the IoT device itself.
|
||||
|
||||
The simplest digital sensor is a button or switch. This is a sensor with two states, on or off.
|
||||
|
||||

|
||||
|
||||
***A button. Microcontroller by Template / Button by Dan Hetteix - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
Pins on IoT devices such as GPIO pins can measure this signal directly as a 0 or 1. If the voltage sent is the same as the voltage returned, the value read is 1, otherwise the value read is 0. There is no need to convert the signal, it can only be 1 or 0.
|
||||
|
||||
> 💁 Voltages are never exact especially as the components in a sensor will have some resistance, so there is usually a tolerance. For example the GPIO pins on a Raspberry Pi work on 3.3V, and read a return signal above 1.8v as a 1, below 1.8v as 0.
|
||||
|
||||
* 3.3V goes into the button. The button is off so 0v comes out, giving a value of 0
|
||||
* 3.3V goes into the button. The button is on so 3.3V comes out, giving a value of 1
|
||||
|
||||
More advanced digital sensors read analog values, then convert them using on-board ADCs to digital signals. For example a digital temperature sensor will still use a thermocouple in the same way as an analog sensor, and will still measure the change in voltage caused by the resistance of the thermocouple at the current temperature. Instead of returning an analog value and relying on the device or connector board to convert to a digital signal, an ADC built into the sensor will convert the value and send it as a series of 0s and 1s to the IoT device. These 0s and 1s are sent in the same way as the digital signal for a button with 1 being full voltage and 0 being 0v.
|
||||
|
||||

|
||||
|
||||
***A digital temperature sensor. Temperature by Vectors Market / Microcontroller by Template - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
Sending digital data allows sensors to become more complex and send more detailed data, even encrypted data for secure sensors. One example is a camera. This is a sensor that captures an image and sends it as digital data containing that image, usually in a compressed format such as JPEG, to be read by the IoT device. It can even stream video by capturing images and sending either the complete image frame by frame, or a compressed video stream.
|
||||
|
||||
## What are actuators?
|
||||
|
||||
Actuators are the opposite of sensors - they convert an electrical signal from your IoT device into an interaction with the physical world such as emitting light or sound, or moving a motor.
|
||||
|
||||
Some common actuators include:
|
||||
|
||||
* LED - these emit light when turned on
|
||||
* Speaker - these emil sound based on the signal sent to them, from a basic buzzer to an audio speaker that can play music
|
||||
* Stepper motor - these convert a signal into a defined amount of rotation, such as turning a dial 90°
|
||||
* Relay - these are switches that can be turned on or off by an electrical signal. They allow a small voltage from an IoT device to turn on larger voltages.
|
||||
* Screens - these are more complex actuators and show information on a multi-segment display. Screens vary from simple LED displays to high-resolution video monitors.
|
||||
|
||||
✅ Do some research. What actuators does your phone have?
|
||||
|
||||
## Use an actuator
|
||||
|
||||
Follow the relevant guide below to add an actuator to your IoT device, controlled by the sensor, to build an IoT nightlight. It will gather light levels from the light sensor, and use an actuator in the form of an LED to emit light when the detected light level is too low.
|
||||
|
||||

|
||||
|
||||
***A flow chart of the assignment showing light levels being read and checked, and the LED begin controlled. ldr by Eucalyp / LED by abderraouf omara - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
* [Arduino - Wio Terminal](wio-terminal-actuator.md)
|
||||
* [Single-board computer - Raspberry Pi](pi-actuator.md)
|
||||
* [Single-board computer - Virtual device](virtual-device-actuator.md)
|
||||
|
||||
## Actuator types
|
||||
|
||||
Like sensors, actuators are either analog or digital.
|
||||
|
||||
### Analog actuators
|
||||
|
||||
Analog actuators take an analog signal and convert it into some kind of interaction, where the interaction changes based off the voltage supplied.
|
||||
|
||||
One example is a dimmable light, such as the ones you might have in your house. The amount of voltage supplied to the light determines how bright it is.
|
||||
|
||||

|
||||
|
||||
***A light controlled by the voltage output by an IoT device. Idea by Pause08 / Microcontroller by Template - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
Like with sensors, the actual IoT device works on digital signals, not analog. This means to send an analog signal, the IoT device needs a digital to analog converter (DAC), either on the IoT device directly, or on a connector board. This will convert the 0s and 1s from the IoT device to an analog voltage that the actuator can use.
|
||||
|
||||
✅ What do you think happens if the IoT device sends a higher voltage than the actuator can handle? ⛔️ DO NOT test this out.
|
||||
|
||||
#### Pulse-Width Modulation
|
||||
|
||||
Another option for converting digital signals from an IoT device to an analog signal is pulse-width modulation. This involves sending lots of short digital pulses that act as if it was an analog signal.
|
||||
|
||||
For example, you can use PWM to control the speed of a motor.
|
||||
|
||||
imagine you are controlling a motor with a 5V supply. You send a short pulse to your motor, switching the voltage to high (5V) for two hundredths of a second (0.02s). In that time your motor can rotate one tenth of a rotation, or 36°. The signal then pauses for two hundredths of a second (0.02s), sending a low signal (0v). Each cycle of on then off lasts 0.04s. The cycle then repeats.
|
||||
|
||||

|
||||
|
||||
***PWM rotation of a motor at 150RPM. motor by Bakunetsu Kaito / Microcontroller by Template - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
This means in one second you have 25 5V pulses of 0.02s that rotate the motor, each followed by 0.02s pause of 0v not rotating the motor. Each pulse rotates the motor one tenth of a rotation, meaning the motor completes 2.5 rotations per second. You've used a digital signal to rotate the motor at 2.5 rotations per second, or 150 ([revolutions per minute](https://wikipedia.org/wiki/Revolutions_per_minute), a non-standard measure of rotational velocity).
|
||||
|
||||
```output
|
||||
25 pulses per second x 0.1 rotations per pulse = 2.5 rotations per second
|
||||
2.5 rotations per second x 60 seconds in a minute = 150rpm
|
||||
```
|
||||
|
||||
> 🎓 When a PWM signal is on for half the time, and off for half it is referred to as a [50% duty cycle](https://wikipedia.org/wiki/Duty_cycle). Duty cycles are measured as the percentage time the signal is in the on state compared to the off state.
|
||||
|
||||

|
||||
|
||||
***PWM rotation of a motor at 75RPM. motor by Bakunetsu Kaito / Microcontroller by Template - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
You can change the motor speed by changing the size of the pulses. For example, with the same motor you can keep the same cycle time of 0.04s, with the on pulse halved to 0.01s, and the off pulse increasing to 0.03s. You have the same number of pulses per second (25), but each on pulse is half the length. A half length pulse only turns the motor one twentieth of a rotation, and at 25 pulses a second will complete 1.25 rotations per second, or 75rpm. By changing the pulse speed of a digital signal you've halved the speed of an analog motor.
|
||||
|
||||
```output
|
||||
25 pulses per second x 0.05 rotations per pulse = 1.25 rotations per second
|
||||
1.25 rotations per second x 60 seconds in a minute = 75rpm
|
||||
```
|
||||
|
||||
✅ How would you keep the motor rotation smooth, especially at low speeds? Would you use a small number long pulses with long pauses, or lots of very short pulses with very short pauses?
|
||||
|
||||
> 💁 Some sensors also use PWM to convert analog signals to digital signals.
|
||||
|
||||
> 🎓 You can read more on pulse-width modulation on the [pulse-width modulation page on Wikipedia](https://wikipedia.org/wiki/Pulse-width_modulation).
|
||||
|
||||
### Digital actuators
|
||||
|
||||
Digital actuators, like digital sensors, either have two states controlled by a high or low voltage, or have a DAC built in so can convert a digital signal to an analog one.
|
||||
|
||||
One simple digital actuator is an LED. When a device sends a digital signal of 1, a high voltage is sent that lights the LED. When a digital signal of 0 is sent, the voltage drops to 0v and the LED turns off.
|
||||
|
||||

|
||||
|
||||
***An LED turning on and off depending on voltage. LED by abderraouf omara / Microcontroller by Template - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
✅ What other simple 2-state actuators can you think of? One example is a solenoid, which is an electromagnet that can be activated to do things like move a door bolt locking/unlocking a door.
|
||||
|
||||
More advanced digital actuators, such as screens require the digital data to be sent in certain formats. They usually come with libraries that make it easier to send the correct data to control them.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Challenge
|
||||
|
||||
The challenge in the last two lessons was to list as many IoT devices as you can that are in your home, school or workplace and decide if they are built around microcontrollers or single-board computers, or even a mixture of both.
|
||||
|
||||
For every device you listed, what sensors and actuators are they connected to? What is the purpose of each sensor and actuator connected to these devices.
|
||||
|
||||
## Post-lecture quiz
|
||||
|
||||
[Post-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/6)
|
||||
|
||||
## Review & Self Study
|
||||
|
||||
* Read up on electricity and circuits on [ThingLearn](http://www.thinglearn.com/essentials/).
|
||||
* Read about the different types of temperature sensors on the [Seeed Studios Temperature Sensors guide](https://www.seeedstudio.com/blog/2019/10/14/temperature-sensors-for-arduino-projects/)
|
||||
* Read about LEDs on the [Wikipedia LED page](https://wikipedia.org/wiki/Light-emitting_diode)
|
||||
|
||||
## Assignment
|
||||
|
||||
[Research sensors and actuators](assignment.md)
|
@ -0,0 +1,17 @@
|
||||
# Research sensors and actuators
|
||||
|
||||
## Instructions
|
||||
|
||||
This lesson covered sensors and actuators. Research and describe one sensor and one actuator that can be used with an IoT dev kit, including:
|
||||
|
||||
* What it does
|
||||
* The electronics/hardware used inside
|
||||
* Is it analog or digital
|
||||
* What the units and range of inputs or measurements is
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| Describe a sensor | Described a sensor including with details for all 4 sections listed above. | Described a sensor, but was only able to provide 2-3 of the sections above | Described a sensor, but was only able to provide 1 of the sections above |
|
||||
| Describe an actuator | Described an actuator including with details for all 4 sections listed above. | Described an actuator, but was only able to provide 2-3 of the sections above | Described an actuator, but was only able to provide 1 of the sections above |
|
@ -0,0 +1,17 @@
|
||||
import time
|
||||
from grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from grove.grove_led import GroveLed
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
if light < 200:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
time.sleep(1)
|
@ -0,0 +1,20 @@
|
||||
import time
|
||||
from counterfit_connection import CounterFitConnection
|
||||
from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from counterfit_shims_grove.grove_led import GroveLed
|
||||
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
if light < 200:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
time.sleep(1)
|
@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
from counterfit_shims_grove.counterfit_connection import CounterFitConnection
|
||||
import time
|
||||
from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from counterfit_shims_grove.grove_led import GroveLed
|
||||
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
if light < 200:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
time.sleep(1)
|
@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
@ -0,0 +1,14 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:seeed_wio_terminal]
|
||||
platform = atmelsam
|
||||
board = seeed_wio_terminal
|
||||
framework = arduino
|
@ -0,0 +1,32 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
while (!Serial)
|
||||
; // Wait for Serial to be ready
|
||||
|
||||
delay(1000);
|
||||
|
||||
pinMode(WIO_LIGHT, INPUT);
|
||||
pinMode(D0, OUTPUT);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
int light = analogRead(WIO_LIGHT);
|
||||
Serial.print("Light value: ");
|
||||
Serial.println(light);
|
||||
|
||||
if (light < 200)
|
||||
{
|
||||
digitalWrite(D0, HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(D0, LOW);
|
||||
}
|
||||
|
||||
delay(1000);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
@ -0,0 +1,10 @@
|
||||
import time
|
||||
from grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
time.sleep(1)
|
@ -0,0 +1,13 @@
|
||||
import time
|
||||
from counterfit_connection import CounterFitConnection
|
||||
from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
time.sleep(1)
|
@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
from counterfit_shims_grove.counterfit_connection import CounterFitConnection
|
||||
import time
|
||||
from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from counterfit_shims_grove.grove_led import GroveLed
|
||||
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
if light < 200:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
time.sleep(1)
|
@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
@ -0,0 +1,14 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:seeed_wio_terminal]
|
||||
platform = atmelsam
|
||||
board = seeed_wio_terminal
|
||||
framework = arduino
|
@ -0,0 +1,22 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
while (!Serial)
|
||||
; // Wait for Serial to be ready
|
||||
|
||||
delay(1000);
|
||||
|
||||
pinMode(WIO_LIGHT, INPUT);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
int light = analogRead(WIO_LIGHT);
|
||||
Serial.print("Light value: ");
|
||||
Serial.println(light);
|
||||
|
||||
delay(1000);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
@ -0,0 +1,114 @@
|
||||
# Build a nightlight - Raspberry Pi
|
||||
|
||||
In this part of the lesson, you will add an LED to your Raspberry Pi and use it to create a nightlight.
|
||||
|
||||
## Hardware
|
||||
|
||||
The nightlight now needs an actuator.
|
||||
|
||||
The actuator is an **LED**, a [light-emitting diode](https://wikipedia.org/wiki/Light-emitting_diode) that emits light when current flows through it. This is a digital actuator that has 2 states, on and off. Sending a value of 1 turns the LED on, and 0 turns it off. The LED is an external Grove actuator and needs to be connected to the Grove Base hat on the Raspberry Pi.
|
||||
|
||||
The nightlight logic in pseudo-code is:
|
||||
|
||||
```output
|
||||
Check the light level.
|
||||
If the light is less than 200
|
||||
Turn the LED on
|
||||
Otherwise
|
||||
Turn the LED off
|
||||
```
|
||||
|
||||
### Connect the LED
|
||||
|
||||
The Grove LED comes as a module with a selection of LEDs, allowing you to chose the color.
|
||||
|
||||
#### Task
|
||||
|
||||
Connect the LED.
|
||||
|
||||

|
||||
|
||||
1. Pick your favorite LED and insert the legs into the two holes on the LED module.
|
||||
|
||||
LEDs are light-emitting diodes, and diodes are electronic devices that can only carry current one way. This means the LED needs to be connected the right way round, otherwise it won't work.
|
||||
|
||||
One of the legs of the LED is the positive pin, the other is the negative pin. The LED is not perfectly round, and is slightly flatter on one side. The side that is slightly flatter is the negative pin. When you connect the LED to the module, make sure the pin by the rounded side is connected to the socket marked **+** on the outside of the module, and the flatter side is connected to the socket closer to the middle of the module.
|
||||
|
||||
1. The LED module has a spin button that allows you to control the brightness. Turn this all the way up to start with by rotating it anti-clockwise as far as it will go using a small Phillips head screwdriver.
|
||||
|
||||
1. Insert one end of a Grove cable into the socket on the LED module. It will only go in one way round.
|
||||
|
||||
1. With the Raspberry Pi powered off, connect the other end of the Grove cable to the digital socket marked **D5** on the Grove Base hat attached to the Pi. This socket is the second from the left, on the row of sockets next to the GPIO pins.
|
||||
|
||||

|
||||
|
||||
## Program the nightlight
|
||||
|
||||
The nightlight can now be programmed using the Grove light sensor and the Grove LED.
|
||||
|
||||
### Task
|
||||
|
||||
Program the nightlight.
|
||||
|
||||
1. Power up the Pi and wait for it to boot
|
||||
|
||||
1. Open the nightlight project in VS Code that you created in the previous part of this assignment, either running directly on the Pi or connected using the Remote SSH extension.
|
||||
|
||||
1. Add the following code to the `app.py` file to connect to import a required library. This should be added to the top, below the other `import` lines.
|
||||
|
||||
```python
|
||||
from grove.grove_led import GroveLed
|
||||
```
|
||||
|
||||
The `from grove.grove_led import GroveLed` statement imports the `GroveLed` from the Grove Python libraries. This library has code to interact with a Grove LED.
|
||||
|
||||
1. Add the following code after the `light_sensor` declaration to create an instance of the class that manages the LED:
|
||||
|
||||
```python
|
||||
led = GroveLed(5)
|
||||
```
|
||||
|
||||
The line `led = GroveLed(5)` creates an instance of the `GroveLed` class connecting to pin **D5** - the digital Grove pin that the LED is connected to.
|
||||
|
||||
1. Add a check inside the `while` loop, and before the `time.sleep` to check the light levels and turn the LED on or off:
|
||||
|
||||
```python
|
||||
if light < 200:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
```
|
||||
|
||||
This code checks the `light` value. If this is less than 200 it calls the `on` method of the `GroveLed` class which sends a digital value of 1 to the LED, turning it on. If the light value is greater than or equal to 200 it calls the `off` method, sending a digital value of 0 to the LED, turning it off.
|
||||
|
||||
> 💁 This code should be indented to the same level as the `print('Light level:', light)` line to be inside the while loop!
|
||||
|
||||
> 💁 When sending digital values to actuators, a 0 value is 0v, and a 1 value is the max voltage for the device. For the Raspberry Pi with Grove sensors and actuators, the 1 voltage is 3.3V.
|
||||
|
||||
1. From the VS Code Terminal, run the following to run your Python app:
|
||||
|
||||
```sh
|
||||
python3 app.py
|
||||
```
|
||||
|
||||
You should see light values being output to the console.
|
||||
|
||||
```output
|
||||
pi@raspberrypi:~/nightlight $ python3 app.py
|
||||
Light level: 634
|
||||
Light level: 634
|
||||
Light level: 634
|
||||
Light level: 230
|
||||
Light level: 104
|
||||
Light level: 290
|
||||
```
|
||||
|
||||
1. Cover and uncover the light sensor. Notice how the LED will light up if the light level is 200 or less, and turn off when the light level is greater than 200.
|
||||
|
||||
> 💁 If the LED doesn't turn on, make sure it is connected the right way round, and the spin button is set to full on.
|
||||
|
||||

|
||||
|
||||
> 💁 You can find this code in the [code-actuator/pi](code-actuator/pi) folder.
|
||||
|
||||
😀 Your nightlight program was a success!
|
@ -0,0 +1,98 @@
|
||||
# Build a nightlight - Raspberry Pi
|
||||
|
||||
In this part of the lesson, you will add a light sensor to your Raspberry Pi.
|
||||
|
||||
## Hardware
|
||||
|
||||
The sensor for this lesson is a **light sensor** that uses a [photodiode](https://wikipedia.org/wiki/Photodiode) to convert light to an electrical signal. This is an analog sensor that sends an integer value from 0 to 1,000 indicating a relative amount of light that doesn't map to any standard unit of measurement such as [lux](https://wikipedia.org/wiki/Lux).
|
||||
|
||||
The light sensor is an eternal Grove sensor and needs to be connected to the Grove Base hat on the Raspberry Pi.
|
||||
|
||||
### Connect the light sensor
|
||||
|
||||
The Grove light sensor that is used to detect the light levels needs to be connected to the Raspberry Pi.
|
||||
|
||||
#### Task
|
||||
|
||||
Connect the light sensor
|
||||
|
||||

|
||||
|
||||
1. Insert one end of a Grove cable into the socket on the light sensor module. It will only go in one way round.
|
||||
|
||||
1. With the Raspberry Pi powered off, connect the other end of the Grove cable to the analog socket marked **A0** on the Grove Base hat attached to the Pi. This socket is the second from the right, on the row of sockets next to the GPIO pins.
|
||||
|
||||

|
||||
|
||||
## Program the light sensor
|
||||
|
||||
The device can now be programmed using the Grove light sensor.
|
||||
|
||||
### Task
|
||||
|
||||
Program the device.
|
||||
|
||||
1. Power up the Pi and wait for it to boot
|
||||
|
||||
1. Open the nightlight project in VS Code that you created in the previous part of this assignment, either running directly on the Pi or connected using the Remote SSH extension.
|
||||
|
||||
1. Open the `app.py` file and remove all code from it
|
||||
|
||||
1. Add the following code to the `app.py` file to import some required libraries:
|
||||
|
||||
```python
|
||||
import time
|
||||
from grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
```
|
||||
|
||||
The `import time` statement imports the `time` module that will be used later in this assignment.
|
||||
|
||||
The `from grove.grove_light_sensor_v1_2 import GroveLightSensor` statement imports the `GroveLightSensor` from the Grove Python libraries. This library has code to interact with a Grove light sensor, and was installed globally during the Pi setup.
|
||||
|
||||
1. Add the following code after the code above to create an instance of the class that manages the light sensor:
|
||||
|
||||
```python
|
||||
light_sensor = GroveLightSensor(0)
|
||||
```
|
||||
|
||||
The line `light_sensor = GroveLightSensor(0)` creates an instance of the `GroveLightSensor` class connecting to pin **A0** - the analog Grove pin that the light sensor is connected to.
|
||||
|
||||
> 💁 All the sockets have unique pin numbers. Pins 0, 2, 4, and 6 are analog pins, pins 5, 16, 18, 22, 24, and 26 are digital pins.
|
||||
|
||||
1. Add an infinite loop after the code above to poll the light sensor value and print it to the console:
|
||||
|
||||
```python
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
```
|
||||
|
||||
This will read the current light level on a scale of 0-1,023 using the `light` property of the `GroveLightSensor` class. This property reads the analog value from the pin. This value is then printed to the console.
|
||||
|
||||
1. Add a small sleep of one second at the end of the `loop` as the light levels don't need to be checked continuously. A sleep reduces the power consumption of the device.
|
||||
|
||||
```python
|
||||
time.sleep(1)
|
||||
```
|
||||
|
||||
1. From the VS Code Terminal, run the following to run your Python app:
|
||||
|
||||
```sh
|
||||
python3 app.py
|
||||
```
|
||||
|
||||
You should see light values being output to the console. Cover and uncover the light sensor to see the values change:
|
||||
|
||||
```output
|
||||
pi@raspberrypi:~/nightlight $ python3 app.py
|
||||
Light level: 634
|
||||
Light level: 634
|
||||
Light level: 634
|
||||
Light level: 230
|
||||
Light level: 104
|
||||
Light level: 290
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code-sensor/pi](code-sensor/pi) folder.
|
||||
|
||||
😀 Adding a sensor to your nightlight program was a success!
|
@ -0,0 +1,110 @@
|
||||
# Build a nightlight - Virtual IoT Hardware
|
||||
|
||||
In this part of the lesson, you will add an LED to your virtual IoT device and use it to create a nightlight.
|
||||
|
||||
## Virtual Hardware
|
||||
|
||||
The nightlight needs one actuator, created in the CounterFit app.
|
||||
|
||||
The actuator is an **LED**. In a physical IoT device, it would be a [light-emitting diode](https://wikipedia.org/wiki/Light-emitting_diode) that emits light when current flows through it. This is a digital actuator that has 2 states, on and off. Sending a value of 1 turns the LED on, and 0 turns it off.
|
||||
|
||||
The nightlight logic in pseudo-code is:
|
||||
|
||||
```output
|
||||
Check the light level.
|
||||
If the light is less than 200
|
||||
Turn the LED on
|
||||
Otherwise
|
||||
Turn the LED off
|
||||
```
|
||||
|
||||
### Add the sensors to CounterFit
|
||||
|
||||
To use a virtual LED, you need to add it to the CounterFit app
|
||||
|
||||
#### Task
|
||||
|
||||
Add the LED to the CounterFit app.
|
||||
|
||||
1. Make sure the CounterFit web app is running from the previous part of this assignment. If not, start it and re-add the light sensor.
|
||||
|
||||
1. Create an LED:
|
||||
|
||||
1. In the *Create actuator* box in the *Actuator* pane, drop down the *Actuator type* box and select *LED*.
|
||||
|
||||
1. Set the *Pin* to *5*
|
||||
|
||||
1. Select the **Add** button to create the LED on Pin 5
|
||||
|
||||

|
||||
|
||||
The LED will be created and appear in the actuators list.
|
||||
|
||||

|
||||
|
||||
Once the LED has been created, you can change the color using the *Color* picker. Select the **Set** button to change the color after you have selected it.
|
||||
|
||||
### Program the nightlight
|
||||
|
||||
The nightlight can now be programmed using the CounterFit light sensor and LED.
|
||||
|
||||
#### Task
|
||||
|
||||
Program the nightlight.
|
||||
|
||||
1. Open the nightlight project in VS Code that you created in the previous part of this assignment. Kill and re-create the terminal to ensure it is running using the virtual environment if necessary.
|
||||
|
||||
1. Open the `app.py` file
|
||||
|
||||
1. Add the following code to the `app.py` file to connect to import a required library. This should be added to the top, below the other `import` lines.
|
||||
|
||||
```python
|
||||
from counterfit_shims_grove.grove_led import GroveLed
|
||||
```
|
||||
|
||||
The `from counterfit_shims_grove.grove_led import GroveLed` statement imports the `GroveLed` from the CounterFit Grove shim Python libraries. This library has code to interact with an LED created in the CounterFit app.
|
||||
|
||||
1. Add the following code after the `light_sensor` declaration to create an instance of the class that manages the LED:
|
||||
|
||||
```python
|
||||
led = GroveLed(5)
|
||||
```
|
||||
|
||||
The line `led = GroveLed(5)` creates an instance of the `GroveLed` class connecting to pin **5** - the CounterFit Grove pin that the LED is connected to.
|
||||
|
||||
1. Add a check inside the `while` loop, and before the `time.sleep` to check the light levels and turn the LED on or off:
|
||||
|
||||
```python
|
||||
if light < 200:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
```
|
||||
|
||||
This code checks the `light` value. If this is less than 200 it calls the `on` method of the `GroveLed` class which sends a digital value of 1 to the LED, turning it on. If the light value is greater than or equal to 200 it calls the `off` method, sending a digital value of 0 to the LED, turning it off.
|
||||
|
||||
> 💁 This code should be indented to the same level as the `print('Light level:', light)` line to be inside the while loop!
|
||||
|
||||
1. From the VS Code Terminal, run the following to run your Python app:
|
||||
|
||||
```sh
|
||||
python3 app.py
|
||||
```
|
||||
|
||||
You should see light values being output to the console.
|
||||
|
||||
```output
|
||||
(.venv) ➜ GroveTest python3 app.py
|
||||
Light level: 143
|
||||
Light level: 244
|
||||
Light level: 246
|
||||
Light level: 253
|
||||
```
|
||||
|
||||
1. Change the *Value* or the *Random* settings to vary the light level above and below 200. You will see the LED turn on and off.
|
||||
|
||||

|
||||
|
||||
> 💁 You can find this code in the [code-actuator/virtual-device](code-actuator/virtual-device) folder.
|
||||
|
||||
😀 Your nightlight program was a success!
|
@ -0,0 +1,111 @@
|
||||
# Build a nightlight - Virtual IoT Hardware
|
||||
|
||||
In this part of the lesson, you will add a light sensor to your virtual IoT device.
|
||||
|
||||
## Virtual Hardware
|
||||
|
||||
The nightlight needs one sensor, created in the CounterFit app.
|
||||
|
||||
The sensor is a **light sensor**. In a physical IoT device, it would be a [photodiode](https://wikipedia.org/wiki/Photodiode) that converts light to an electrical signal. Light sensors are analog sensors that sends an integer value indicating a relative amount of light, that doesn't map to any standard unit of measurement such as [lux](https://wikipedia.org/wiki/Lux).
|
||||
|
||||
### Add the sensors to CounterFit
|
||||
|
||||
To use a virtual light sensor, you need to add it to the CounterFit app
|
||||
|
||||
#### Task
|
||||
|
||||
Add the light sensor to the CounterFit app.
|
||||
|
||||
1. Make sure the CounterFit web app is running from the previous part of this assignment. If not, start it.
|
||||
|
||||
1. Create a light sensor:
|
||||
|
||||
1. In the *Create sensor* box in the *Sensors* pane, drop down the *Sensor type* box and select *Light*.
|
||||
|
||||
1. Leave the *Units* set to *NoUnits*
|
||||
|
||||
1. Ensure the *Pin* is set to *0*
|
||||
|
||||
1. Select the **Add** button to create the light sensor on Pin 0
|
||||
|
||||

|
||||
|
||||
The light sensor will be created and appear in the sensors list.
|
||||
|
||||

|
||||
|
||||
## Program the light sensor
|
||||
|
||||
The device can now be programmed to use the built in light sensor.
|
||||
|
||||
### Task
|
||||
|
||||
Program the device.
|
||||
|
||||
|
||||
1. Open the nightlight project in VS Code that you created in the previous part of this assignment. Kill and re-create the terminal to ensure it is running using the virtual environment if necessary.
|
||||
|
||||
1. Open the `app.py` file
|
||||
|
||||
1. Add the following code to the top of `app.py` file with the rest of the `import` statements to connect to import some required libraries:
|
||||
|
||||
```python
|
||||
import time
|
||||
from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
```
|
||||
|
||||
The `import time` statement imports the Python `time` module that will be used later in this assignment.
|
||||
|
||||
The `from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor` statement imports the `GroveLightSensor` from the CounterFit Grove shim Python libraries. This library has code to interact with a light sensor created in the CounterFit app.
|
||||
|
||||
1. Add the following code to the bottom of the file to create instances of classes that manage the light sensor:
|
||||
|
||||
```python
|
||||
light_sensor = GroveLightSensor(0)
|
||||
```
|
||||
|
||||
The line `light_sensor = GroveLightSensor(0)` creates an instance of the `GroveLightSensor` class connecting to pin **0** - the CounterFit Grove pin that the light sensor is connected to.
|
||||
|
||||
1. Add an infinite loop after the code above to poll the light sensor value and print it to the console:
|
||||
|
||||
```python
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
```
|
||||
|
||||
This will read the current light level using the `light` property of the `GroveLightSensor` class. This property reads the analog value from the pin. This value is then printed to the console.
|
||||
|
||||
1. Add a small sleep of one second at the end of the `while` loop as the light levels don't need to be checked continuously. A sleep reduces the power consumption of the device.
|
||||
|
||||
```python
|
||||
time.sleep(1)
|
||||
```
|
||||
|
||||
1. From the VS Code Terminal, run the following to run your Python app:
|
||||
|
||||
```sh
|
||||
python3 app.py
|
||||
```
|
||||
|
||||
You should see light values being output to the console. Initially this value will be 0.
|
||||
|
||||
1. From the CounterFit app, change the value of the light sensor that will be read by the app. You can do this in one of two ways:
|
||||
|
||||
* Enter a number in the *Value* box for the light sensor, then select the **Set** button. The number you enter will be the value returned by the sensor.
|
||||
|
||||
* Check the *Random* checkbox, and enter a *Min* and *Max* value, then select the **Set** button. Every time the sensor reads a value, it will read a random number between *Min* and *Max*.
|
||||
|
||||
You should see the values you set appearing in the console. Change the *Value* or the *Random* settings to see the value change.
|
||||
|
||||
```output
|
||||
(.venv) ➜ GroveTest python3 app.py
|
||||
Light level: 143
|
||||
Light level: 244
|
||||
Light level: 246
|
||||
Light level: 253
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code-sensor/virtual-device](code-sensor/virtual-device) folder.
|
||||
|
||||
😀 Your nightlight program was a success!
|
@ -0,0 +1,110 @@
|
||||
# Build a nightlight - Wio Terminal
|
||||
|
||||
In this part of the lesson, you will add an LED to your Wio Terminal and use it to create a nightlight.
|
||||
|
||||
## Hardware
|
||||
|
||||
The nightlight now needs an actuator.
|
||||
|
||||
The actuator is an **LED**, a [light-emitting diode](https://wikipedia.org/wiki/Light-emitting_diode) that emits light when current flows through it. This is a digital actuator that has 2 states, on and off. Sending a value of 1 turns the LED on, and 0 turns it off. This is an external Grove actuator and needs to be connected to the Wio Terminal.
|
||||
|
||||
The nightlight logic in pseudo-code is:
|
||||
|
||||
```output
|
||||
Check the light level.
|
||||
If the light is less than 200
|
||||
Turn the LED on
|
||||
Otherwise
|
||||
Turn the LED off
|
||||
```
|
||||
|
||||
### Connect the LED
|
||||
|
||||
The Grove LED comes as a module with a selection of LEDs, allowing you to chose the color.
|
||||
|
||||
#### Task
|
||||
|
||||
Connect the LED.
|
||||
|
||||

|
||||
|
||||
1. Pick your favorite LED and insert the legs into the two holes on the LED module.
|
||||
|
||||
LEDs are light-emitting diodes, and diodes are electronic devices that can only carry current one way. This means the LED needs to be connected the right way round, otherwise it won't work.
|
||||
|
||||
One of the legs of the LED is the positive pin, the other is the negative pin. The LED is not perfectly round, and is slightly flatter on one side. The side that is slightly flatter is the negative pin. When you connect the LED to the module, make sure the pin by the rounded side is connected to the socket marked **+** on the outside of the module, and the flatter side is connected to the socket closer to the middle of the module.
|
||||
|
||||
1. The LED module has a spin button that allows you to control the brightness. Turn this all the way up to start with byt rotating it anti-clockwise as far as it will go using a small Phillips head screwdriver.
|
||||
|
||||
1. Insert one end of a Grove cable into the socket on the LED module. It will only go in one way round.
|
||||
|
||||
1. With the Wio Terminal disconnected from your computer or other power supply, connect the other end of the Grove cable to the right-hand side Grove socket on the Wio Terminal as you look at the screen. This is the socket farthest away from the power button.
|
||||
|
||||
> 💁 The right-hand Grove socket can be used with analog or digital sensors and actuators. The left-hand socket is for I<sup>2</sup>C and digital sensors and actuators only. I<sup>2</sup>C will be covered in a later lesson.
|
||||
|
||||

|
||||
|
||||
## Program the nightlight
|
||||
|
||||
The nightlight can now be programmed using the built in light sensor and the Grove LED.
|
||||
|
||||
### Task
|
||||
|
||||
Program the nightlight.
|
||||
|
||||
1. Open the nightlight project in VS Code that you created in the previous part of this assignment
|
||||
|
||||
1. Add the following line to the bottom of the `setup` function:
|
||||
|
||||
```cpp
|
||||
pinMode(D0, OUTPUT);
|
||||
```
|
||||
|
||||
This line configures the pin used to communicate with the LED via the Grove port.
|
||||
|
||||
The `D0` pin is the digital pin for the right-hand Grove socket. This pin is set to `OUTPUT`, meaning it connects to an actuator and data will be written to the pin.
|
||||
|
||||
1. Add the following code immediately before the `delay` in the loop function:
|
||||
|
||||
```cpp
|
||||
if (light < 200)
|
||||
{
|
||||
digitalWrite(D0, HIGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(D0, LOW);
|
||||
}
|
||||
```
|
||||
|
||||
This code checks the `light` value. If this is less than 200 it sends a `HIGH` value to the `D0` digital pin. This `HIGH` is a value of 1, turning on the LED. If the light is greater than or equal to 200, a `LOW` value of 0 is sent to the pin, turning the LED off.
|
||||
|
||||
> 💁 When sending digital values to actuators, a LOW value is 0v, and a HIGH value is the max voltage for the device. For the Wio Terminal, the HIGH voltage is 3.3V.
|
||||
|
||||
1. Reconnect the Wio Terminal to your computer, and upload the new code as you did before.
|
||||
|
||||
1. Connect the Serial Monitor. You should see light values being output to the terminal.
|
||||
|
||||
```output
|
||||
> Executing task: platformio device monitor <
|
||||
|
||||
--- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
|
||||
--- More details at http://bit.ly/pio-monitor-filters
|
||||
--- Miniterm on /dev/cu.usbmodem101 9600,8,N,1 ---
|
||||
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
|
||||
Light value: 4
|
||||
Light value: 5
|
||||
Light value: 4
|
||||
Light value: 158
|
||||
Light value: 343
|
||||
Light value: 348
|
||||
Light value: 344
|
||||
```
|
||||
|
||||
1. Cover and uncover the light sensor. Notice how the LED will light up if the light level is 200 or less, and turn off when the light level is greater than 200.
|
||||
|
||||

|
||||
|
||||
> 💁 You can find this code in the [code-actuator/wio-terminal](code-actuator/wio-terminal) folder.
|
||||
|
||||
😀 Your nightlight program was a success!
|
@ -0,0 +1,73 @@
|
||||
# Add a sensor - Wio Terminal
|
||||
|
||||
In this part of the lesson, you will use the light sensor on your Wio Terminal.
|
||||
|
||||
## Hardware
|
||||
|
||||
The sensor for this lesson is a **light sensor** that uses a [photodiode](https://wikipedia.org/wiki/Photodiode) to convert light to an electrical signal. This is an analog sensor that sends an integer value from 0 to 1,023 indicating a relative amount of light that doesn't map to any standard unit of measurement such as [lux](https://wikipedia.org/wiki/Lux).
|
||||
|
||||
The light sensor is built into the Wio Terminal and is visible through the clear plastic window on the back.
|
||||
|
||||

|
||||
|
||||
## Program the light sensor
|
||||
|
||||
The device can now be programmed to use the built in light sensor.
|
||||
|
||||
### Task
|
||||
|
||||
Program the device.
|
||||
|
||||
1. Open the nightlight project in VS Code that you created in the previous part of this assignment
|
||||
|
||||
1. Add the following line to the bottom of the `setup` function:
|
||||
|
||||
```cpp
|
||||
pinMode(WIO_LIGHT, INPUT);
|
||||
```
|
||||
|
||||
This line configures the pins used to communicate with the sensor hardware.
|
||||
|
||||
The `WIO_LIGHT` pin is the number of the GPIO pin connected to the on-board light sensor. This pin is set to `INPUT`, meaning it connects to a sensor and data will be read from the pin.
|
||||
|
||||
1. Delete the contents of the `loop` function.
|
||||
|
||||
1. Add the following code to the now empty `loop` function.
|
||||
|
||||
```cpp
|
||||
int light = analogRead(WIO_LIGHT);
|
||||
Serial.print("Light value: ");
|
||||
Serial.println(light);
|
||||
```
|
||||
|
||||
This code reads an analog value from the `WIO_LIGHT` pin. This reads a value from 0-1,023 from the on-board light sensor. This value is then sent to the serial port so you can see it in the Serial Monitor when this code is running. `Serial.print` writes the text without a new line on the end, so each line will start with `Light value:` and end with the actual light value.
|
||||
|
||||
1. Add a small delay of one second (1,000ms) at the end of the `loop` as the light levels don't need to be checked continuously. A delay reduces the power consumption of the device.
|
||||
|
||||
```cpp
|
||||
delay(1000);
|
||||
```
|
||||
|
||||
1. Reconnect the Wio Terminal to your computer, and upload the new code as you did before.
|
||||
|
||||
1. Connect the Serial Monitor. You should see light values being output to the terminal. Cover and uncover the light sensor on the back of the Wio Terminal to see the values change.
|
||||
|
||||
```output
|
||||
> Executing task: platformio device monitor <
|
||||
|
||||
--- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
|
||||
--- More details at http://bit.ly/pio-monitor-filters
|
||||
--- Miniterm on /dev/cu.usbmodem101 9600,8,N,1 ---
|
||||
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
|
||||
Light value: 4
|
||||
Light value: 5
|
||||
Light value: 4
|
||||
Light value: 158
|
||||
Light value: 343
|
||||
Light value: 348
|
||||
Light value: 344
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code-sensor/wio-terminal](code-sensor/wio-terminal) folder.
|
||||
|
||||
😀 Adding a sensor to your nightlight program was a success!
|
@ -0,0 +1,444 @@
|
||||
# Connect your device to the Internet
|
||||
|
||||
Add a sketchnote if possible/appropriate
|
||||
|
||||

|
||||
|
||||
## Pre-lecture quiz
|
||||
|
||||
[Pre-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/7)
|
||||
|
||||
## Introduction
|
||||
|
||||
The **I** in IoT stands for **Internet** - the cloud connectivity and services that enable a lot of the features of IoT devices, from gathering measurements from the sensors connected to the device, to sending messages to control the actuators. IoT devices typically connect to a single cloud IoT service using a standard communication protocol, and that service is connected to the rest of your IoT application, from AI services to make smart decisions around your data, to web apps for control or reporting.
|
||||
|
||||
> 🎓 Data gathered from sensors and sent to the cloud is called telemetry.
|
||||
|
||||
IoT devices can receive messages from the cloud. Often the messages contain commands - that is instructions to perform an action either internally (such as reboot or update firmware), or using an actuator (such as turning on a light).
|
||||
|
||||
This lesson introduces some of the communication protocols IoT devices can use to connect to the cloud, and the types of data they might send or receive. You will also get hands on with them both, adding Internet control to your nightlight, moving the LED control logic to 'server' code running locally.
|
||||
|
||||
In this lesson we'll cover:
|
||||
|
||||
* [Communication protocols](#communication-protocols)
|
||||
* [Message Queueing Telemetry Transport (MQTT)](#message-queueing-telemetry-transport-mqtt)
|
||||
* [Telemetry](#telemetry)
|
||||
* [Commands](#commands)
|
||||
|
||||
## Communication protocols
|
||||
|
||||
There are a number of popular communication protocols used by IoT devices to communicate with the Internet. The most popular are based around publish/subscribe messaging via some kind of broker. The IoT devices connect to the broker and publish telemetry and subscribe to commands, the cloud services also connect to the broker and subscribe to all the telemetry messages and publishes commands either to specific devices, or to groups of devices.
|
||||
|
||||

|
||||
|
||||
***IoT devices connect to a broker and publish telemetry and subscribe to commands. Cloud services connect to the broker and subscribe to all telemetry and send commands to specific devices. broadcast by RomStu / Microcontroller by Template / Cloud by Debi Alpa Nugraha - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
MQTT is the most popular, and is covered in this lesson. Others include AMQP and HTTP/HTTPS.
|
||||
|
||||
## Message Queueing Telemetry Transport (MQTT)
|
||||
|
||||
[MQTT](http://mqtt.org) is a lightweight, open standard messaging protocol that can send messages between devices. It was designed in 1999 to monitor oil pipelines, before being released as an open standard 15 years later by IBM.
|
||||
|
||||
MQTT has a single broker and multiple clients. All clients connect to the broker, and the broker routes messages to the relevant clients. Messages are routed using named topics, rather than being sent direct to an individual client. A client can publish to a topic, and any clients that subscribe to that topic will receive the message.
|
||||
|
||||

|
||||
|
||||
***IoT device publishing telemetry on the /telemetry topic, and the cloud service subscribing to that topic. Microcontroller by Template / Cloud by Debi Alpa Nugraha - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
✅ Do some research. If you have a lot of IoT devices, how can you ensure your MQTT broker can handle all the messages?
|
||||
|
||||
### Connect your IoT device to MQTT
|
||||
|
||||
The first part in adding Internet control to your nightlight is connecting it to an MQTT broker.
|
||||
|
||||
#### Task
|
||||
|
||||
Connect your device to an MQTT broker.
|
||||
|
||||
In this part of the lesson, you will connect your IoT nightlight to the Internet to allow it to be remotely controlled. Later in this lesson your IoT device will send a telemetry message over MQTT to a public MQTT broker with the light level, where it will be picked up by some server code that you will write. This code will check the light level and send a command message back to the device telling it to turn the LED on or off.
|
||||
|
||||
The real-world use case for such a setup could be to gather data from multiple light sensors before deciding to turn on lights, in a location that has a lot of lights, such as a stadium. This could stop the lights being turned on if only one sensor was covered by cloud or a bird, but the other sensors detected enough light.
|
||||
|
||||
✅ What other situations would require data from multiple sensors to be evaluated before sending commands?
|
||||
|
||||
Rather than dealing with the complexities of setting up an MQTT broker as part of this assignment, you can use a public test server that runs [Eclipse Mosquitto](https://www.mosquitto.org), an open-source MQTT broker. This test broker is publicly available at [test.mosquitto.org](https://test.mosquitto.org), and doesn't require an accounts to be set up, making it a great tool for testing MQTT clients and servers.
|
||||
|
||||
> 💁 This test broker is public and not secure. Anyone could be listening to what you publish, so should not be used with any data that needs to be kept private
|
||||
|
||||

|
||||
|
||||
***A flow chart of the assignment showing light levels being read and checked, and the LED begin controlled. ldr by Eucalyp / LED by abderraouf omara - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
Follow the relevant step below to connect your device to the MQTT broker:
|
||||
|
||||
* [Arduino - Wio Terminal](wio-terminal-mqtt.md)
|
||||
* [Single-board computer - Raspberry Pi/Virtual IoT device](single-board-computer-mqtt.md)
|
||||
|
||||
### A deeper dive into MQTT
|
||||
|
||||
Topics can have a hierarchy, and clients can subscribe to different levels of the hierarchy using wildcards. For example you can send temperature telemetry messages to `/telemetry/temperature` and humidity messages to `/telemetry/humidity`, then in your cloud app subscribe to `/telemetry/*` to receive both the temperature and humidity telemetry messages.
|
||||
|
||||
Messages can be sent with a quality of service (QoS), which determines the guarantees of the message being received.
|
||||
|
||||
* At most once - the message is sent only once and the client and broker take no additional steps to acknowledge delivery (fire and forget).
|
||||
* At least once - the message is re-tried by the sender multiple times until acknowledgement is received (acknowledged delivery).
|
||||
* Exactly once - the sender and receiver engage in a two-level handshake to ensure only one copy of the message is received (assured delivery).
|
||||
|
||||
✅ What situations might require an assured delivery message over a fire and forget message?
|
||||
|
||||
Although the name is Message Queueing, it doesn't actually support message queues. This means that if a client is disconnected, then reconnects it won't receive messages sent during the disconnect except for those messages that it had already started to process using the QoS process. Messages can have a retained flag set on them. If this is set, the MQTT broker will store the last message sent on a topic with this flag, and send this to any clients who later subscribe to the topic. This way the clients will always get the latest message.
|
||||
|
||||
MQTT also supports a keep alive function that checks to see if the connection is still alive during long gaps between messages.
|
||||
|
||||
> 🦟 [Mosquitto from the Eclipse Foundation](https://mosquitto.org) has a free MQTT broker you can run yourself to experiment with MQTT, along with a public MQTT broker you can use to test your code hosted at [test.mosquitto.org](https://test.mosquitto.org).
|
||||
|
||||
MQTT connections can be public and open, or encrypted and secured using usernames and passwords, or certificates.
|
||||
|
||||
> 💁 MQTT communicates over TCP/IP, the same underlying network protocol as HTTP, but on a different port. You can also use MQTT over websockets to communicate with web apps running in a browser, or in situations where firewalls or other networking rules block standard MQTT connections.
|
||||
|
||||
## Telemetry
|
||||
|
||||
The word telemetry is derived from Greek roots meaning to measure remotely. Telemetry is the act of gathering data from sensors and sending it to the cloud.
|
||||
|
||||
> 💁 One of the earliest telemetry devices was invented in France in 1874 and sent real-time weather and snow depths from Mont Blanc to Paris. It used physical wires as wireless technologies were not available at the time.
|
||||
|
||||
Lets look back at the example of the smart thermostat from Lesson 1.
|
||||
|
||||

|
||||
|
||||
***An Internet connected thermostat using multiple room sensors. Temperature by Vectors Market / Microcontroller by Template / dial by Jamie Dickinson / heater by Pascal Heß / mobile phone and Calendar by Alice-vector / Cloud by Debi Alpa Nugraha / smart sensor by Andrei Yushchenko / weather by Adrien Coquet - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
The thermostat has temperature sensors to gather telemetry. It would most likely have one temperature sensor built in, and it might connect to multiple external temperature sensors over a wireless protocol such as BLE.
|
||||
|
||||
An example of the telemetry data it would send could be:
|
||||
|
||||
| Name | Value | Description |
|
||||
| ---- | ----- | ----------- |
|
||||
| `thermostat_temperature` | 18°C | The temperature measured by the thermostat's built in temperature sensor |
|
||||
| `livingroom_temperature` | 19°C | The temperature measured by a remote temperature sensor that has been named `livingroom` to identify the room it is in |
|
||||
| `bedroom_temperature` | 21°C | The temperature measured by a remote temperature sensor that has been named `bedroom` to identify the room it is in |
|
||||
|
||||
The cloud service can then use this telemetry data to make decisions around what commands to send to control the heating.
|
||||
|
||||
### Send telemetry from your IoT device
|
||||
|
||||
The next part in adding Internet control to your nightlight is sending the light level telemetry to the MQTT broker on a telemetry topic.
|
||||
|
||||
#### Task
|
||||
|
||||
Send light level telemetry to the MQTT broker.
|
||||
|
||||
Data is sent encoded as JSON - short for JavaScript Object Notation, a standard for encoding data in text using key/value pairs.
|
||||
|
||||
✅ If you've not come across JSON before, you can learn more about it on the [JSON.org documentation](https://www.json.org/).
|
||||
|
||||
Follow the relevant step below to send telemetry from your device to the MQTT broker:
|
||||
|
||||
* [Arduino - Wio Terminal](wio-terminal-telemetry.md)
|
||||
* [Single-board computer - Raspberry Pi/Virtual IoT device](single-board-computer-telemetry.md)
|
||||
|
||||
### Receive telemetry from the MQTT broker
|
||||
|
||||
There's no point in sending telemetry if there's nothing on the other end to listen for it. The light level telemetry needs something listening to it to process the data. This 'server' code is the kind of code you wold deploy to a cloud service as part of a larger IoT application, but here you are going to run this code locally on your computer (on on you Pi if you are coding directly on there). The server code consists of a Python app that listens to telemetry messages over MQTT with light levels. Later in this less you will make it reply with a command message with instructions to turn the LED on or off.
|
||||
|
||||
✅ Do some research: What happens to MQTT messages if there is no listener?
|
||||
|
||||
#### Install Python and VS Code
|
||||
|
||||
If you don't have Python and VS Code installed locally, you will need to install them both to code the server. If you are using a virtual device, or are working on your Raspberry Pi you can skip this step.
|
||||
|
||||
##### Task
|
||||
|
||||
Install Python and VS Code.
|
||||
|
||||
1. Install Python. Refer to the [Python downloads page](https://www.python.org/downloads/) for instructions on install the latest version of Python.
|
||||
|
||||
1. Install Visual Studio Code (VS Code). This is the editor you will be using to write your virtual device code in Python. Refer to the [VS Code documentation](https://code.visualstudio.com?WT.mc_id=academic-17441-jabenn) for instructions on installing VS Code.
|
||||
|
||||
> 💁 You are free to use any Python IDE or editor for these lessons if you have a preferred tool, but the lessons will give instructions based off using VS Code.
|
||||
|
||||
1. Install the VS Code Pylance extension. This is an extension for VS Code that provides Python language support. Refer to the [Pylance extension documentation](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance&WT.mc_id=academic-17441-jabenn) for instructions on installing this extension in VS Code.
|
||||
|
||||
#### Configure a Python virtual environment
|
||||
|
||||
One of the powerful features of Python is the ability to install [pip packages](https://pypi.org) - these are packages of code written by other people and published to the Internet. You can install a pip package onto your computer with one command, then use that package in your code. You'll be using pip to install a package to communicate over MQTT.
|
||||
|
||||
By default when you install a package it is available everywhere on your computer, and this can lead to problems with package versions - such as one application depending on one version of a package that breaks when you install a new version for a different application. To work around this problem, you can use a [Python virtual environment](https://docs.python.org/3/library/venv.html), essentially a copy of Python in a dedicated folder, and when you install pip packages they get installed just to that folder.
|
||||
|
||||
##### Task
|
||||
|
||||
Configure a Python virtual environment and install the MQTT pip packages.
|
||||
|
||||
1. From your terminal or command line, run the following at a location of your choice to create and navigate to a new directory:
|
||||
|
||||
```sh
|
||||
mkdir nightlight-server
|
||||
cd nightlight-server
|
||||
```
|
||||
|
||||
1. Now run the following to create a virtual environment in the `.venv` folder
|
||||
|
||||
```sh
|
||||
python3 -m venv .venv
|
||||
```
|
||||
|
||||
> 💁 You need to explicitly call `python3` to create the virtual environment just in case you have Python 2 installed in addition to Python 3 (the latest version). If you have Python2 installed then calling `python` will use Python 2 instead of Python 3
|
||||
|
||||
1. Activate the virtual environment:
|
||||
|
||||
* On Windows run:
|
||||
|
||||
```cmd
|
||||
.venv\Scripts\activate.bat
|
||||
```
|
||||
|
||||
* On macOS or Linux, run:
|
||||
|
||||
```cmd
|
||||
source ./.venv/bin/activate
|
||||
```
|
||||
|
||||
1. Once the virtual environment has been activated, the default `python` command will run the version of Python that was used to create the virtual environment. Run the following to see this:
|
||||
|
||||
```sh
|
||||
python --version
|
||||
```
|
||||
|
||||
You should see the following:
|
||||
|
||||
```output
|
||||
(.venv) ➜ nightlight-server python --version
|
||||
Python 3.9.1
|
||||
```
|
||||
|
||||
> 💁 Your Python version may be different - as long as it's version 3.6 or higher you are good. If not, delete this folder, install a newer version of Python and try again.
|
||||
|
||||
1. Run the following commands to install the pip package for [Paho-MQTT](https://pypi.org/project/paho-mqtt/), a popular MQTT library.
|
||||
|
||||
```sh
|
||||
pip install paho-mqtt
|
||||
```
|
||||
|
||||
This pip package will only be installed in the virtual environment, and will not be available outside of this.
|
||||
|
||||
#### Write the server code
|
||||
|
||||
The server code can now be written in Python.
|
||||
|
||||
##### Task
|
||||
|
||||
Write the server code.
|
||||
|
||||
1. From your terminal or command line, run the following inside the virtual environment to create a Python file called `app.py`:
|
||||
|
||||
* From Windows run:
|
||||
|
||||
```cmd
|
||||
type nul > app.py
|
||||
```
|
||||
|
||||
* On macOS or Linux, run:
|
||||
|
||||
```cmd
|
||||
touch app.py
|
||||
```
|
||||
|
||||
1. Open the current folder in VS Code:
|
||||
|
||||
```sh
|
||||
code .
|
||||
```
|
||||
|
||||
1. When VS Code launches, it will activate the Python virtual environment. You will see this in the bottom status bar:
|
||||
|
||||

|
||||
|
||||
1. If the VS Code Terminal is already running when VS Code starts up, it won't have the virtual environment activated in it. The easiest thing to do is kill the terminal using the **Kill the active terminal instance** button:
|
||||
|
||||

|
||||
|
||||
1. Launch a new VS Code Terminal by selecting *Terminal -> New Terminal, or pressing `` CTRL+` ``. The new terminal will load the virtual environment, and you will see the call to activate this in the terminal, as well as having the name of the virtual environment (`.venv`) in the prompt:
|
||||
|
||||
```output
|
||||
➜ nightlight source .venv/bin/activate
|
||||
(.venv) ➜ nightlight
|
||||
```
|
||||
|
||||
1. Open the `app.py` file from the VS Code explorer and add the following code:
|
||||
|
||||
```python
|
||||
import json
|
||||
import time
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
client_name = id + 'nightlight_server'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
def handle_telemetry(client, userdata, message):
|
||||
payload = json.loads(message.payload.decode())
|
||||
print("Message received:", payload)
|
||||
|
||||
mqtt_client.subscribe(client_telemetry_topic)
|
||||
mqtt_client.on_message = handle_telemetry
|
||||
|
||||
while True:
|
||||
time.sleep(2)
|
||||
```
|
||||
|
||||
Replace `<ID>` on line 6 with the unique ID you used when creating your device code.
|
||||
|
||||
⚠️ This **must** be the same ID that you used on your device, or the server code won't subscribe or publish to the right topic.
|
||||
|
||||
This code creates an MQTT client with a unique name, and connects to the *test.mosquitto.org* broker. It then starts a processing loop that runs in on a background thread listening for messages on any subscribed topics.
|
||||
|
||||
The client then subscribes to messages on the telemetry topic, and defines a function that is called when a message is received. When a telemetry message is received, the `handle_telemetry` function is called, printing the message received to the console.
|
||||
|
||||
Finally an infinite loop keeps the application running. The MQTT client is listening to messages on a background thread and runs all the time the main application is running.
|
||||
|
||||
1. From the VS Code terminal, run the following to run your Python app:
|
||||
|
||||
```sh
|
||||
python app.py
|
||||
```
|
||||
|
||||
The app will start listening to messages from the IoT device.
|
||||
|
||||
1. Make sure your device is running and sending telemetry messages. Adjust the light levels detected by your physical or virtual device. You will see messages being received in the terminal.
|
||||
|
||||
```output
|
||||
(.venv) ➜ nightlight-server python app.py
|
||||
Message received: {'light': 0}
|
||||
Message received: {'light': 400}
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code-server/server](code-server/server) folder.
|
||||
|
||||
### How often should telemetry be sent?
|
||||
|
||||
One important consideration with telemetry is how often to measure and send the data? The answer is - it depends. If you measure often you can respond faster to changes in measurements, but you use more power, more bandwidth, generate more data and need more cloud resources to process. You need to measure often enough, but not too often.
|
||||
|
||||
For a thermostat, measuring every few minutes is probably more than enough as temperatures don't change that often. If you only measure once a day then you could end up heating your house for nighttime temperatures in the middle of a sunny day, whereas if you measure every second you will have thousands of unnecessary duplicated temperature measurements that will eat into the users Internet speed and bandwidth (a problem for people with limited bandwidth plans), use more power which can be a problem for battery powered devices like remote sensors, and increase the cost of the providers cloud computing resources processing and storing them.
|
||||
|
||||
If you are monitoring a data around a piece of machinery in a factory that if it fails could cause catastrophic damage and millions of dollars in lost revenue, thn measuring multiple times a second might be necessary. It's better to waste bandwidth than miss telemetry that indicates that a machine needs to be stopped and fixed before it breaks.
|
||||
|
||||
> 💁 In this situation, you might consider having an edge device to process the telemetry first to reduce reliance on the Internet.
|
||||
|
||||
### Loss of connectivity
|
||||
|
||||
Internet connections can be unreliable, with outages common. What should an IoT device do under these circumstances - should it lose the data, or should it store it until connectivity is restored? Again, the answer is it depends.
|
||||
|
||||
For a thermostat the data can probably be lost as soon as a new temperature measurement has been taken. The heating system doesn't care that 20 minutes ago it was 20.5°C if the temperature is now 19°C, it's the temperature now that determines if the heating should be on or off.
|
||||
|
||||
For machinery you might want to keep the data, especially if it is used to look for trends. There are machine learning models that can detect anomalies in streams of data by looking over data from defined period of time (such as the last hour) and spotting anomalous data. This is often used for predictive maintenance, looking for indications that something might break soon so you can repair or replace before it happens. You might want every bit of telemetry for a machine sent so it can be processed for anomaly detection, so once the IoT device can reconnect it will send all the telemetry generated during the Internet outage.
|
||||
|
||||
IoT device designers should also consider if the IoT device can be used during an Internet outage or loss of signal caused by location. A smart thermostat should be able to make some limited decisions to control heating if it can't send telemetry to the cloud due to an outage.
|
||||
|
||||
[](https://twitter.com/internetofshit/status/1315736960082808832)
|
||||
|
||||
For MQTT to handle a loss of connectivity, the device and server code will need to be responsible for ensuring message delivery if it is needed, for example by requiring that all messages sent are replied to by additional messages on a reply topic, and if not they are queued manually to be replayed later.
|
||||
|
||||
## Commands
|
||||
|
||||
Commands are messages sent by the cloud to a device, instructing it to do something. Most of the time this involves giving some kind of output via an actuator, but it can be an instruction for the device itself, such as to reboot, or gather extra telemetry and return it as a response to the command.
|
||||
|
||||

|
||||
|
||||
***An Internet connected thermostat receiving a command to turn on the heating. Temperature by Vectors Market / Microcontroller by Template / dial by Jamie Dickinson / heater by Pascal Heß / mobile phone and Calendar by Alice-vector / Cloud by Debi Alpa Nugraha / smart sensor by Andrei Yushchenko / weather by Adrien Coquet - all from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
A thermostat could receive a command from the cloud to turn the heating on. Based on the telemetry data from all the sensors, if the cloud service has decided that the heating should be on, so it sends the relevant command.
|
||||
|
||||
### Send commands to the MQTT broker
|
||||
|
||||
The next step for our Internet controlled nightlight is for the server code to send a command back to the IoT device to control the light based off the light levels it senses.
|
||||
|
||||
1. Open the server code in VS Code
|
||||
|
||||
1. Add the following line after the declaration of the `client_telemetry_topic` to define which topic to send commands to:
|
||||
|
||||
```python
|
||||
server_command_topic = id + '/commands'
|
||||
```
|
||||
|
||||
1. Add the following code to the end of the `handle_telemetry` function:
|
||||
|
||||
```python
|
||||
command = { 'led_on' : payload['light'] < 200 }
|
||||
print("Sending message:", command)
|
||||
|
||||
client.publish(server_command_topic, json.dumps(command))
|
||||
```
|
||||
|
||||
This sends a JSON message to the command topic with the value of `led_on` set to true or false depending on if the light is less than 200 or not. If the light is less than 200, true is sent to instruct the device to turn the LED on.
|
||||
|
||||
1. Run the code as before
|
||||
|
||||
1. Adjust the light levels detected by your physical or virtual device. You will see messages being received and commands being sent in the terminal:
|
||||
|
||||
```output
|
||||
(.venv) ➜ nightlight-server python app.py
|
||||
Message received: {'light': 0}
|
||||
Sending message: {'led_on': True}
|
||||
Message received: {'light': 400}
|
||||
Sending message: {'led_on': False}
|
||||
```
|
||||
|
||||
> 💁 The telemetry and commands are being sent on a single topic each. This means telemetry from multiple devices will appear on the same telemetry topic, and commands to multiple devices will appear on the same commands topic. If you wanted to send a command to a specific device, you could use multiple topics, named with a unique device id, such as `/commands/device1`, `/commands/device2`. That way a device can listen on messages just meant for that one device.
|
||||
|
||||
### Handle commands on the IoT device
|
||||
|
||||
Now that commands are being sent from the server, you cna now add code to the IoT device to handle them and control the LED.
|
||||
|
||||
Follow the relevant step below to listen to commands from the MQTT broker:
|
||||
|
||||
* [Arduino - Wio Terminal](wio-terminal-commands.md)
|
||||
* [Single-board computer - Raspberry Pi/Virtual IoT device](single-board-computer-commands.md)
|
||||
|
||||
Once this code is written and running, experiment with changing light levels. Watch the output from the server and device, and watch the LED as you change light levels.
|
||||
|
||||
### Loss of connectivity
|
||||
|
||||
What should a cloud service do if it needs to send a command to an IoT device that is offline? Again, the answer is it depends.
|
||||
|
||||
If the latest command overrides an earlier one then the earlier ones can probably be ignored. If a cloud service sends a command to turn the heating on, then sends a command to turn it off, then the on command can be ignored and not resent.
|
||||
|
||||
If the commands need to be processed in sequence, such as move a robot arm up, then close a grabber then they need to be sent in order once connectivity is restored.
|
||||
|
||||
✅ How could the device or server code ensure commands are always sent and handled in order over MQTT if needed?
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Challenge
|
||||
|
||||
The challenge in the last three lessons was to list as many IoT devices as you can that are in your home, school or workplace and decide if they are built around microcontrollers or single-board computers, or even a mixture of both, and thing about what sensors and actuators they are using.
|
||||
|
||||
For these devices, think about what messages they might be sending or receiving. What telemetry do they send? What messages or commands might they receive? Do you think they are secure?
|
||||
|
||||
## Post-lecture quiz
|
||||
|
||||
[Post-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/8)
|
||||
|
||||
## Review & Self Study
|
||||
|
||||
Read more on MQTT on the [MQTT Wikipedia page](https://wikipedia.org/wiki/MQTT).
|
||||
|
||||
Try running an MQTT broker yourself using [Mosquitto](https://www.mosquitto.org) and connect to it from your IoT device and server code.
|
||||
|
||||
> 💁 Tip - by default Mosquitto doesn't allow anonymous connections (that is connecting without a username and password), and doesn't allow connections from outside of the computer it's running on.
|
||||
> You can fix this with a [`mosquitto.conf` config file](https://www.mosquitto.org/man/mosquitto-conf-5.html) with the following:
|
||||
>
|
||||
> ```sh
|
||||
> listener 1883 0.0.0.0
|
||||
> allow_anonymous true
|
||||
> ```
|
||||
|
||||
## Assignment
|
||||
|
||||
[Compare and contrast MQTT with other communication protocols](assignment.md)
|
@ -0,0 +1,14 @@
|
||||
# Compare and contrast MQTT with other communication protocols
|
||||
|
||||
## Instructions
|
||||
|
||||
This lesson covered MQTT as a communication protocols. There are others, including AMQP and HTTP/HTTPS.
|
||||
|
||||
Research these both and compare/contract them with MQTT. Think about power usage, security, and message persistence if connections are lost.
|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| Compare AMQP to MQTT | Is able to compare and contrast AMQP to MQTT and covers power, security, and message persistance. | Is partly able to compare and contrast AMQP to MQTT and covers two of power, security, and message persistance. | Is partly able to compare and contrast AMQP to MQTT and covers one of power, security, and message persistance. |
|
||||
| Compare HTTP/HTTPS to MQTT | Is able to compare and contrast HTTP/HTTPS to MQTT and covers power, security, and message persistance. | Is partly able to compare and contrast HTTP/HTTPS to MQTT and covers two of power, security, and message persistance. | Is partly able to compare and contrast HTTP/HTTPS to MQTT and covers one of power, security, and message persistance. |
|
@ -0,0 +1,39 @@
|
||||
import time
|
||||
from grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from grove.grove_led import GroveLed
|
||||
import json
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
server_command_topic = id + '/commands'
|
||||
client_name = id + 'nightlight_client'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
def handle_command(client, userdata, message):
|
||||
payload = json.loads(message.payload.decode())
|
||||
print("Message received:", payload)
|
||||
|
||||
if payload['led_on']:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
mqtt_client.subscribe(server_command_topic)
|
||||
mqtt_client.on_message = handle_command
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
mqtt_client.publish(client_telemetry_topic, json.dumps({'light' : light}))
|
||||
|
||||
time.sleep(5)
|
@ -0,0 +1,24 @@
|
||||
import json
|
||||
import time
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
client_name = id + '_nightlight_server'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
def handle_telemetry(client, userdata, message):
|
||||
payload = json.loads(message.payload.decode())
|
||||
print("Message received:", payload)
|
||||
|
||||
mqtt_client.subscribe(client_telemetry_topic)
|
||||
mqtt_client.on_message = handle_telemetry
|
||||
|
||||
while True:
|
||||
time.sleep(2)
|
@ -0,0 +1,40 @@
|
||||
import time
|
||||
from counterfit_connection import CounterFitConnection
|
||||
from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from counterfit_shims_grove.grove_led import GroveLed
|
||||
import json
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
server_command_topic = id + '/commands'
|
||||
client_name = id + 'nightlight_client'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
def handle_command(client, userdata, message):
|
||||
payload = json.loads(message.payload.decode())
|
||||
print("Message received:", payload)
|
||||
|
||||
if payload['led_on']:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
mqtt_client.subscribe(server_command_topic)
|
||||
mqtt_client.on_message = handle_command
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
mqtt_client.publish(client_telemetry_topic, json.dumps({'light' : light}))
|
@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
@ -0,0 +1,22 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:seeed_wio_terminal]
|
||||
platform = atmelsam
|
||||
board = seeed_wio_terminal
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
knolleary/PubSubClient @ 2.8
|
||||
bblanchon/ArduinoJson @ 6.17.3
|
||||
seeed-studio/Seeed Arduino rpcWiFi @ 1.0.3
|
||||
seeed-studio/Seeed Arduino FS @ 2.0.2
|
||||
seeed-studio/Seeed Arduino SFUD @ 2.0.1
|
||||
seeed-studio/Seeed Arduino rpcUnified @ 2.1.3
|
||||
seeed-studio/Seeed_Arduino_mbedtls @ 3.0.1
|
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// WiFi credentials
|
||||
const char *SSID = "<SSID>";
|
||||
const char *PASSWORD = "<PASSWORD>";
|
||||
|
||||
// MQTT settings
|
||||
const string ID = "<ID>";
|
||||
|
||||
const string BROKER = "test.mosquitto.org";
|
||||
const string CLIENT_NAME = ID + "nightlight_client";
|
||||
|
||||
const string CLIENT_TELEMETRY_TOPIC = ID + "/telemetry";
|
||||
const string SERVER_COMMAND_TOPIC = ID + "/commands";
|
@ -0,0 +1,112 @@
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <rpcWiFi.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void connectWiFi()
|
||||
{
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
Serial.println("Connecting to WiFi..");
|
||||
WiFi.begin(SSID, PASSWORD);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
Serial.println("Connected!");
|
||||
}
|
||||
|
||||
WiFiClient wioClient;
|
||||
PubSubClient client(wioClient);
|
||||
|
||||
void clientCallback(char *topic, uint8_t *payload, unsigned int length)
|
||||
{
|
||||
char buff[length + 1];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
buff[i] = (char)payload[i];
|
||||
}
|
||||
buff[length] = '\0';
|
||||
|
||||
Serial.print("Message received:");
|
||||
Serial.println(buff);
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
deserializeJson(doc, buff);
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
|
||||
bool led_on = obj["led_on"];
|
||||
|
||||
if (led_on)
|
||||
digitalWrite(D0, HIGH);
|
||||
else
|
||||
digitalWrite(D0, LOW);
|
||||
}
|
||||
|
||||
void reconnectMQTTClient()
|
||||
{
|
||||
while (!client.connected())
|
||||
{
|
||||
Serial.print("Attempting MQTT connection...");
|
||||
|
||||
if (client.connect(CLIENT_NAME.c_str()))
|
||||
{
|
||||
Serial.println("connected");
|
||||
client.subscribe(SERVER_COMMAND_TOPIC.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("Retying in 5 seconds - failed, rc=");
|
||||
Serial.println(client.state());
|
||||
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createMQTTClient()
|
||||
{
|
||||
client.setServer(BROKER.c_str(), 1883);
|
||||
client.setCallback(clientCallback);
|
||||
reconnectMQTTClient();
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
while (!Serial)
|
||||
; // Wait for Serial to be ready
|
||||
|
||||
delay(1000);
|
||||
|
||||
pinMode(WIO_LIGHT, INPUT);
|
||||
pinMode(D0, OUTPUT);
|
||||
|
||||
connectWiFi();
|
||||
createMQTTClient();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
reconnectMQTTClient();
|
||||
client.loop();
|
||||
|
||||
int light = analogRead(WIO_LIGHT);
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
doc["light"] = light;
|
||||
|
||||
string telemetry;
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
serializeJson(obj, telemetry);
|
||||
|
||||
Serial.print("Sending telemetry ");
|
||||
Serial.println(telemetry.c_str());
|
||||
|
||||
client.publish(CLIENT_TELEMETRY_TOPIC.c_str(), telemetry.c_str());
|
||||
|
||||
delay(2000);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
@ -0,0 +1,29 @@
|
||||
import time
|
||||
from grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from grove.grove_led import GroveLed
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_name = id + 'nightlight_client'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
print("MQTT connected!")
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
if light < 200:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
time.sleep(1)
|
@ -0,0 +1,32 @@
|
||||
import time
|
||||
from counterfit_connection import CounterFitConnection
|
||||
from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from counterfit_shims_grove.grove_led import GroveLed
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_name = id + 'nightlight_client'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
print("MQTT connected!")
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
print('Light level:', light)
|
||||
|
||||
if light < 200:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
time.sleep(1)
|
@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
@ -0,0 +1,21 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:seeed_wio_terminal]
|
||||
platform = atmelsam
|
||||
board = seeed_wio_terminal
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
knolleary/PubSubClient @ 2.8
|
||||
seeed-studio/Seeed Arduino rpcWiFi @ 1.0.3
|
||||
seeed-studio/Seeed Arduino FS @ 2.0.2
|
||||
seeed-studio/Seeed Arduino SFUD @ 2.0.1
|
||||
seeed-studio/Seeed Arduino rpcUnified @ 2.1.3
|
||||
seeed-studio/Seeed_Arduino_mbedtls @ 3.0.1
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// WiFi credentials
|
||||
const char *SSID = "<SSID>";
|
||||
const char *PASSWORD = "<PASSWORD>";
|
||||
|
||||
// MQTT settings
|
||||
const string ID = "<ID>";
|
||||
|
||||
const string BROKER = "test.mosquitto.org";
|
||||
const string CLIENT_NAME = ID + "nightlight_client";
|
@ -0,0 +1,71 @@
|
||||
#include <Arduino.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <rpcWiFi.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void connectWiFi()
|
||||
{
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
Serial.println("Connecting to WiFi..");
|
||||
WiFi.begin(SSID, PASSWORD);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
Serial.println("Connected!");
|
||||
}
|
||||
|
||||
WiFiClient wioClient;
|
||||
PubSubClient client(wioClient);
|
||||
|
||||
void reconnectMQTTClient()
|
||||
{
|
||||
while (!client.connected())
|
||||
{
|
||||
Serial.print("Attempting MQTT connection...");
|
||||
|
||||
if (client.connect(CLIENT_NAME.c_str()))
|
||||
{
|
||||
Serial.println("connected");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("Retying in 5 seconds - failed, rc=");
|
||||
Serial.println(client.state());
|
||||
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createMQTTClient()
|
||||
{
|
||||
client.setServer(BROKER.c_str(), 1883);
|
||||
reconnectMQTTClient();
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
while (!Serial)
|
||||
; // Wait for Serial to be ready
|
||||
|
||||
delay(1000);
|
||||
|
||||
pinMode(WIO_LIGHT, INPUT);
|
||||
pinMode(D0, OUTPUT);
|
||||
|
||||
connectWiFi();
|
||||
createMQTTClient();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
reconnectMQTTClient();
|
||||
client.loop();
|
||||
|
||||
delay(2000);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
@ -0,0 +1,30 @@
|
||||
import json
|
||||
import time
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
server_command_topic = id + '/commands'
|
||||
client_name = id + 'nightlight_server'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
def handle_telemetry(client, userdata, message):
|
||||
payload = json.loads(message.payload.decode())
|
||||
print("Message received:", payload)
|
||||
|
||||
command = { 'led_on' : payload['light'] < 200 }
|
||||
print("Sending message:", command)
|
||||
|
||||
client.publish(server_command_topic, json.dumps(command))
|
||||
|
||||
mqtt_client.subscribe(client_telemetry_topic)
|
||||
mqtt_client.on_message = handle_telemetry
|
||||
|
||||
while True:
|
||||
time.sleep(2)
|
@ -0,0 +1,30 @@
|
||||
import time
|
||||
from grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from grove.grove_led import GroveLed
|
||||
import paho.mqtt.client as mqtt
|
||||
import json
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
client_name = id + 'nightlight_client'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
print("MQTT connected!")
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
telemetry = json.dumps({'light' : light})
|
||||
|
||||
print("Sending telemetry ", telemetry)
|
||||
|
||||
mqtt_client.publish(client_telemetry_topic, telemetry)
|
||||
|
||||
time.sleep(5)
|
@ -0,0 +1,33 @@
|
||||
import time
|
||||
from counterfit_connection import CounterFitConnection
|
||||
from counterfit_shims_grove.grove_light_sensor_v1_2 import GroveLightSensor
|
||||
from counterfit_shims_grove.grove_led import GroveLed
|
||||
import paho.mqtt.client as mqtt
|
||||
import json
|
||||
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
light_sensor = GroveLightSensor(0)
|
||||
led = GroveLed(5)
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
client_name = id + 'nightlight_client'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
print("MQTT connected!")
|
||||
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
telemetry = json.dumps({'light' : light})
|
||||
|
||||
print("Sending telemetry ", telemetry)
|
||||
|
||||
mqtt_client.publish(client_telemetry_topic, telemetry)
|
||||
|
||||
time.sleep(5)
|
@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
@ -0,0 +1,22 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:seeed_wio_terminal]
|
||||
platform = atmelsam
|
||||
board = seeed_wio_terminal
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
knolleary/PubSubClient @ 2.8
|
||||
seeed-studio/Seeed Arduino rpcWiFi @ 1.0.3
|
||||
seeed-studio/Seeed Arduino FS @ 2.0.2
|
||||
seeed-studio/Seeed Arduino SFUD @ 2.0.1
|
||||
seeed-studio/Seeed Arduino rpcUnified @ 2.1.3
|
||||
seeed-studio/Seeed_Arduino_mbedtls @ 3.0.1
|
||||
bblanchon/ArduinoJson @ 6.17.3
|
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// WiFi credentials
|
||||
const char *SSID = "<SSID>";
|
||||
const char *PASSWORD = "<PASSWORD>";
|
||||
|
||||
// MQTT settings
|
||||
const string ID = "<ID>";
|
||||
|
||||
const string BROKER = "test.mosquitto.org";
|
||||
const string CLIENT_NAME = ID + "nightlight_client";
|
||||
|
||||
const string CLIENT_TELEMETRY_TOPIC = ID + "/telemetry";
|
@ -0,0 +1,86 @@
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJSON.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <rpcWiFi.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void connectWiFi()
|
||||
{
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
Serial.println("Connecting to WiFi..");
|
||||
WiFi.begin(SSID, PASSWORD);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
Serial.println("Connected!");
|
||||
}
|
||||
|
||||
WiFiClient wioClient;
|
||||
PubSubClient client(wioClient);
|
||||
|
||||
void reconnectMQTTClient()
|
||||
{
|
||||
while (!client.connected())
|
||||
{
|
||||
Serial.print("Attempting MQTT connection...");
|
||||
|
||||
if (client.connect(CLIENT_NAME.c_str()))
|
||||
{
|
||||
Serial.println("connected");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("Retying in 5 seconds - failed, rc=");
|
||||
Serial.println(client.state());
|
||||
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createMQTTClient()
|
||||
{
|
||||
client.setServer(BROKER.c_str(), 1883);
|
||||
reconnectMQTTClient();
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
while (!Serial)
|
||||
; // Wait for Serial to be ready
|
||||
|
||||
delay(1000);
|
||||
|
||||
pinMode(WIO_LIGHT, INPUT);
|
||||
pinMode(D0, OUTPUT);
|
||||
|
||||
connectWiFi();
|
||||
createMQTTClient();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
reconnectMQTTClient();
|
||||
client.loop();
|
||||
|
||||
int light = analogRead(WIO_LIGHT);
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
doc["light"] = light;
|
||||
|
||||
string telemetry;
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
serializeJson(obj, telemetry);
|
||||
|
||||
Serial.print("Sending telemetry ");
|
||||
Serial.println(telemetry.c_str());
|
||||
|
||||
client.publish(CLIENT_TELEMETRY_TOPIC.c_str(), telemetry.c_str());
|
||||
|
||||
delay(2000);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
|
||||
This directory is intended for PlatformIO Unit Testing and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/page/plus/unit-testing.html
|
@ -0,0 +1,53 @@
|
||||
# Control your nightlight over the Internet - Virtual IoT Hardware and Raspberry Pi
|
||||
|
||||
In this part of the lesson, you will subscribe to commands sent from an MQTT broker to your Raspberry Pi or virtual IoT device.
|
||||
|
||||
## Subscribe to commands
|
||||
|
||||
The next step is to subscribe to the commands sent from the MQTT broker, and respond to them.
|
||||
|
||||
### Task
|
||||
|
||||
Subscribe to commands.
|
||||
|
||||
1. Open the nightlight project in VS Code.
|
||||
|
||||
1. If you are using a virtual IoT device, ensure the terminal is running the virtual environment
|
||||
|
||||
1. Add the following code after the definitions of the `client_telemetry_topic`:
|
||||
|
||||
```python
|
||||
server_command_topic = id + '/commands'
|
||||
```
|
||||
|
||||
The `server_command_topic` is the MQTT topic the device will subscribe to to receive LED commands.
|
||||
|
||||
1. Add the following code just above the main loop, after the `mqtt_client.loop_start()` line:
|
||||
|
||||
```python
|
||||
def handle_command(client, userdata, message):
|
||||
payload = json.loads(message.payload.decode())
|
||||
print("Message received:", payload)
|
||||
|
||||
if payload['led_on']:
|
||||
led.on()
|
||||
else:
|
||||
led.off()
|
||||
|
||||
mqtt_client.subscribe(server_command_topic)
|
||||
mqtt_client.on_message = handle_command
|
||||
```
|
||||
|
||||
This code defines a function, `handle_command`, that reads a message as a JSON document and looks for the value of the `led_on` property. If it is set to `True` the LED is turned on, otherwise it is turned off.
|
||||
|
||||
The MQTT client subscribes on the topic that the server will send messages on, and sets the `handle_command` function to be called when a message is received.
|
||||
|
||||
> 💁 The `on_message` handler is called for all topics subscribed to. If you later write code that listens to multiple topics, you can get the topic that the message was sent to from the `message` object passed to the handler function.
|
||||
|
||||
1. Run the code in the same way as you ran the code from the previous part of the assignment. If you are using a virtual IoT device, then make sure the CounterFit app is running and the light sensor and LED have been created on the correct pins.
|
||||
|
||||
1. Adjust the light levels detected by your physical or virtual device. You will see messages being received and commands being sent in the terminal. You will also see the LED being turned on and off depending on the light level.
|
||||
|
||||
> 💁 You can find this code in the [code-commands/virtual-device](code-commands/virtual-device) folder or the [code-commands/pi](code-commands/pi) folder.
|
||||
|
||||
😀 You have successfully coded your device to respond to commands from an MQTT broker.
|
@ -0,0 +1,79 @@
|
||||
# Control your nightlight over the Internet - Virtual IoT Hardware and Raspberry Pi
|
||||
|
||||
The IoT device needs to be coded to communicate with *test.mosquitto.org* using MQTT to send telemetry values with the light sensor reading, and receive commands to control the LED.
|
||||
|
||||
In this part of the lesson, you will connect your Raspberry Pi or virtual IoT device to an MQTT broker.
|
||||
|
||||
## Install the MQTT client package
|
||||
|
||||
To communicate with the MQTT broker, you need to install an MQTT library pip package either on your Pi, or in your virtual environment if you are using a virtual device.
|
||||
|
||||
### Task
|
||||
|
||||
Install the pip package
|
||||
|
||||
1. Open the nightlight project in VS Code.
|
||||
|
||||
1. If you are using a virtual IoT device, ensure the terminal is running the virtual environment.
|
||||
|
||||
1. Run the following command to install the MQTT pip package:
|
||||
|
||||
```sh
|
||||
pip3 install paho-mqtt
|
||||
```
|
||||
|
||||
## Code the device
|
||||
|
||||
The device is ready to code.
|
||||
|
||||
### Task
|
||||
|
||||
Write the device code.
|
||||
|
||||
1. Add the following import to the top of the `app.py` file:
|
||||
|
||||
```python
|
||||
import paho.mqtt.client as mqtt
|
||||
```
|
||||
|
||||
The `paho.mqtt.client` library allows your app to communicate over MQTT.
|
||||
|
||||
1. Add the following code after the definitions of the light sensor and LED:
|
||||
|
||||
```python
|
||||
id = '<ID>'
|
||||
|
||||
client_name = id + 'nightlight_client'
|
||||
```
|
||||
|
||||
Replace `<ID>` with a unique ID that will be used the name of this device client, and later for the topics that this device publishes and subscribes to. The *test.mosquitto.org* broker is public and used by many people, including other students working through this assignment. Having a unique MQTT client name and topic names ensures your code won't clash with anyone elses. You will also need this ID when you are creating the server code later in this assignment.
|
||||
|
||||
> 💁 You can use a website like [GUIDGen](https://www.guidgen.com) to generate a unique ID.
|
||||
|
||||
The `client_name` is a unique name for this MQTT client on the broker.
|
||||
|
||||
1. Add the following code below this new code to create an MQTT client object and connect to the MQTT broker:
|
||||
|
||||
```python
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
print("MQTT connected!")
|
||||
```
|
||||
|
||||
This code creates the client object, connects to the public MQTT broker, and starts a processing loop that runs in a background thread listening for messages on any subscribed topics.
|
||||
|
||||
1. Run the code in the same way as you ran the code from the previous part of the assignment. If you are using a virtual IoT device, then make sure the CounterFit app is running and the light sensor and LED have been created on the correct pins.
|
||||
|
||||
```output
|
||||
(.venv) ➜ nightlight python app.py
|
||||
MQTT connected!
|
||||
Light level: 0
|
||||
Light level: 0
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code-mqtt/virtual-device](code/virtual-device) folder or the [code-mqtt/pi](code/pi) folder.
|
||||
|
||||
😀 You have successfully connected your device to an MQTT broker.
|
@ -0,0 +1,60 @@
|
||||
# Control your nightlight over the Internet - Virtual IoT Hardware and Raspberry Pi
|
||||
|
||||
In this part of the lesson, you will send telemetry with light levels from your Raspberry Pi or virtual IoT device to an MQTT broker.
|
||||
|
||||
## Publish telemetry
|
||||
|
||||
The next step is to create a JSON document with telemetry and send it to the MQTT broker.
|
||||
|
||||
### Task
|
||||
|
||||
Publish telemetry to the MQTT broker.
|
||||
|
||||
1. Open the nightlight project in VS Code.
|
||||
|
||||
1. If you are using a virtual IoT device, ensure the terminal is running the virtual environment
|
||||
|
||||
1. Add the following import to the top of the `app.py` file:
|
||||
|
||||
```python
|
||||
import json
|
||||
```
|
||||
|
||||
The `json` library is used to encode the telemetry as a JSON document.
|
||||
|
||||
1. Add the following after the `client_name` declaration:
|
||||
|
||||
```python
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
```
|
||||
|
||||
The `client_telemetry_topic` is the MQTT topic the device will publish light levels to.
|
||||
|
||||
1. Replace the contents of the `while True:` loop at the end of the file with the following:
|
||||
|
||||
```python
|
||||
while True:
|
||||
light = light_sensor.light
|
||||
telemetry = json.dumps({'light' : light})
|
||||
|
||||
print("Sending telemetry ", telemetry)
|
||||
|
||||
mqtt_client.publish(client_telemetry_topic, telemetry)
|
||||
|
||||
time.sleep(5)
|
||||
```
|
||||
|
||||
This code packages the light level into a JSON document and publishes it to the MQTT broker. It then sleeps to reduce the frequency that messages are sent.
|
||||
|
||||
1. Run the code in the same way as you ran the code from the previous part of the assignment. If you are using a virtual IoT device, then make sure the CounterFit app is running and the light sensor and LED have been created on the correct pins.
|
||||
|
||||
```output
|
||||
(.venv) ➜ nightlight python app.py
|
||||
MQTT connected!
|
||||
Sending telemetry {"light": 0}
|
||||
Sending telemetry {"light": 0}
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code-telemetry/virtual-device](code-telemetry/virtual-device) folder or the [code-telemetry/pi](code-telemetry/pi) folder.
|
||||
|
||||
😀 You have successfully sent telemetry from your device.
|
@ -0,0 +1,79 @@
|
||||
# Control your nightlight over the Internet - Wio Terminal
|
||||
|
||||
In this part of the lesson, you will subscribe to commands sent from an MQTT broker to your Wio Terminal.
|
||||
|
||||
## Subscribe to commands
|
||||
|
||||
The next step is to subscribe to the commands sent from the MQTT broker, and respond to them.
|
||||
|
||||
### Task
|
||||
|
||||
Subscribe to commands.
|
||||
|
||||
1. Open the nightlight project in VS Code.
|
||||
|
||||
1. Add the following code to the bottom of the `config.h` file to define the topic name for the commands:
|
||||
|
||||
```cpp
|
||||
const string SERVER_COMMAND_TOPIC = ID + "/commands";
|
||||
```
|
||||
|
||||
The `SERVER_COMMAND_TOPIC` is the topic the device will subscribe to to receive LED commands.
|
||||
|
||||
1. Add the following line to the end of the `reconnectMQTTClient` function to subscribe to the command topic when the MQTT client is reconnected:
|
||||
|
||||
```cpp
|
||||
client.subscribe(SERVER_COMMAND_TOPIC.c_str());
|
||||
```
|
||||
|
||||
1. Add the following code below the `reconnectMQTTClient` function.
|
||||
|
||||
```cpp
|
||||
void clientCallback(char *topic, uint8_t *payload, unsigned int length)
|
||||
{
|
||||
char buff[length + 1];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
buff[i] = (char)payload[i];
|
||||
}
|
||||
buff[length] = '\0';
|
||||
|
||||
Serial.print("Message received:");
|
||||
Serial.println(buff);
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
deserializeJson(doc, buff);
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
|
||||
bool led_on = obj["led_on"];
|
||||
|
||||
if (led_on)
|
||||
digitalWrite(D0, HIGH);
|
||||
else
|
||||
digitalWrite(D0, LOW);
|
||||
}
|
||||
```
|
||||
|
||||
This function will be the callback that the MQTT client will call when it receives a message from the server.
|
||||
|
||||
The message is received as an array of unsigned 8-bit integers, so needs to be converted to a character array to be treated as text.
|
||||
|
||||
The message contains a JSON document, and is decoded using the ArduinoJson library. The `led_on` property of the JSON document is read, and depending on the value the LED is turned on or off.
|
||||
|
||||
1. Add the following code to the `createMQTTClient` function:
|
||||
|
||||
```cpp
|
||||
client.setCallback(clientCallback);
|
||||
```
|
||||
|
||||
This code sets the `clientCallback` as the callback to be called when a message is received from the MQTT broker.
|
||||
|
||||
> 💁 The `clientCallback` handler is called for all topics subscribed to. If you later write code that listens to multiple topics, you can get the topic that the message was sent to from the `topic` parameter passed to the callback function.
|
||||
|
||||
1. Upload the code to your Wio Terminal, and use the Serial Monitor to see the light levels being sent to the MQTT broker.
|
||||
|
||||
1. Adjust the light levels detected by your physical or virtual device. You will see messages being received and commands being sent in the terminal. You will also see the LED being turned on and off depending on the light level.
|
||||
|
||||
> 💁 You can find this code in the [code-commands/wio-terminal](code-commands/wio-terminal) folder.
|
||||
|
||||
😀 You have successfully coded your device to respond to commands from an MQTT broker.
|
@ -0,0 +1,237 @@
|
||||
# Control your nightlight over the Internet - Wio Terminal
|
||||
|
||||
The IoT device needs to be coded to communicate with *test.mosquitto.org* using MQTT to send telemetry values with the light sensor reading, and receive commands to control the LED.
|
||||
|
||||
In this part of the lesson, you will connect your Wio Terminal to an MQTT broker.
|
||||
|
||||
## Install the WiFi and MQTT Arduino libraries
|
||||
|
||||
To communicate with the MQTT broker, you need to install some Arduino libraries to use the WiFi chip in the Wio Terminal, and communicate with MQTT. When developing for Arduino devices, you can use a wide range of libraries that contain open-source code and implement a huge range of capabilities. Seeed publish libraries for the Wio Terminal that allow it to communicate over WiFi. Other developers have published libraries to communicate with MQTT brokers, and you will be using these with your device.
|
||||
|
||||
These libraries are provided as source code that can be imported automatically into PlatformIO, and compiled for your device. This way Arduino libraries will work on any device that supports the Arduino framework, assuming that the device has any specific hardware needed by that library. Some libraries, such as the Seeed WiFi libraries, are specific to certain hardware.
|
||||
|
||||
Libraries can be installed globally and compiled in if needed, or into a specific project. For this assignment, the libraries will be installed into the project.
|
||||
|
||||
✅ You can learn more about library management and how to find and install libraries in the [PlatformIO library documentation](https://docs.platformio.org/en/latest/librarymanager/index.html).
|
||||
|
||||
### Task
|
||||
|
||||
Install the Arduino libraries.
|
||||
|
||||
1. Open the nightlight project in VS Code.
|
||||
|
||||
1. Add the following to the end of the `platformio.ini` file:
|
||||
|
||||
```ini
|
||||
lib_deps =
|
||||
seeed-studio/Seeed Arduino rpcWiFi @ 1.0.3
|
||||
seeed-studio/Seeed Arduino FS @ 2.0.2
|
||||
seeed-studio/Seeed Arduino SFUD @ 2.0.1
|
||||
seeed-studio/Seeed Arduino rpcUnified @ 2.1.3
|
||||
seeed-studio/Seeed_Arduino_mbedtls @ 3.0.1
|
||||
```
|
||||
|
||||
This imports the Seeed WiFi libraries. The `@ <number>` syntax refers to a specific version number of the library.
|
||||
|
||||
> 💁 You can remove the `@ <number>` to always use the latest version of the libraries, but there's no guarantees the later versions will work with the code below. The code here has been tested with this version of the libraries.
|
||||
|
||||
This is all you need to do to add the libraries. Next time PlatformIO builds the project it will download the source code for these libraries and compile it into your project.
|
||||
|
||||
1. Add the following to the `lib_deps`:
|
||||
|
||||
```ini
|
||||
knolleary/PubSubClient @ 2.8
|
||||
```
|
||||
|
||||
This imports [PubSubClient](https://github.com/knolleary/pubsubclient), an Arduino MQTT client
|
||||
|
||||
## Connect to WiFi
|
||||
|
||||
The Wio Terminal can now be connected to WiFi.
|
||||
|
||||
### Task
|
||||
|
||||
Connect the Wio Terminal to WiFi.
|
||||
|
||||
1. Create a new file in the `src` folder called `config.h`. You can do this by selecting the `src` folder, or the `main.cpp` file inside, and selecting the **New file** button from the explorer. This button only appears when your cursor is over the explorer.
|
||||
|
||||

|
||||
|
||||
1. Add the following code to this file to define constants for your WiFi credentials:
|
||||
|
||||
```cpp
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// WiFi credentials
|
||||
const char *SSID = "<SSID>";
|
||||
const char *PASSWORD = "<PASSWORD>";
|
||||
```
|
||||
|
||||
Replace `<SSID>` with the SSID of your WiFi. Replace `<PASSWORD>` with your WiFi password.
|
||||
|
||||
1. Open the `main.cpp` file
|
||||
|
||||
1. Add the following `#include` directives to the top of the file:
|
||||
|
||||
```cpp
|
||||
#include <PubSubClient.h>
|
||||
#include <rpcWiFi.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include "config.h"
|
||||
```
|
||||
|
||||
This includes header files for the libraries you added earlier, as well as the config header file.
|
||||
|
||||
1. Add the following code above the `setup` function:
|
||||
|
||||
```cpp
|
||||
void connectWiFi()
|
||||
{
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
Serial.println("Connecting to WiFi..");
|
||||
WiFi.begin(SSID, PASSWORD);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
Serial.println("Connected!");
|
||||
}
|
||||
```
|
||||
|
||||
This code loops whilst the device is not connected to WiFi, and tries the connecting using the SSID and password from the config header file.
|
||||
|
||||
1. Add a call to this function at the bottom of the `setup` function, after the pins have been configured.
|
||||
|
||||
```cpp
|
||||
connectWiFi();
|
||||
```
|
||||
|
||||
1. Upload this code to your device to check the WiFi connection is working. You should see this in the serial monitor.
|
||||
|
||||
```output
|
||||
> Executing task: platformio device monitor <
|
||||
|
||||
--- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
|
||||
--- More details at http://bit.ly/pio-monitor-filters
|
||||
--- Miniterm on /dev/cu.usbmodem1101 9600,8,N,1 ---
|
||||
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
|
||||
Connecting to WiFi..
|
||||
Connected!
|
||||
```
|
||||
|
||||
## Connect to MQTT
|
||||
|
||||
Once the Wio Terminal is connected to WiFi, it can connect to the MQTT broker.
|
||||
|
||||
### Task
|
||||
|
||||
Connect to the MQTT broker.
|
||||
|
||||
1. Add the following code to the bottom of the `config.h` file to define the connection details for the MQTT broker:
|
||||
|
||||
```cpp
|
||||
// MQTT settings
|
||||
const string ID = "<ID>";
|
||||
|
||||
const string BROKER = "test.mosquitto.org";
|
||||
const string CLIENT_NAME = ID + "nightlight_client";
|
||||
```
|
||||
|
||||
Replace `<ID>` with a unique ID that will be used the name of this device client, and later for the topics that this device publishes and subscribes to. The *test.mosquitto.org* broker is public and used by many people, including other students working through this assignment. Having a unique MQTT client name and topic names ensures your code won't clash with anyone elses. You will also need this ID when you are creating the server code later in this assignment.
|
||||
|
||||
> 💁 You can use a website like [GUIDGen](https://www.guidgen.com) to generate a unique ID.
|
||||
|
||||
The `BROKER` is the URL of the MQTT broker.
|
||||
|
||||
The `CLIENT_NAME` is a unique name for this MQTT client on the broker.
|
||||
|
||||
1. Open the `main.cpp` file, and add the following code below the `connectWiFi` function and above the `setup` function:
|
||||
|
||||
```cpp
|
||||
WiFiClient wioClient;
|
||||
PubSubClient client(wioClient);
|
||||
```
|
||||
|
||||
This code creates a WiFi client using the Wio Terminal WiFI libraries, and uses it to create an MQTT client.
|
||||
|
||||
1. Below this code, add the following:
|
||||
|
||||
```cpp
|
||||
void reconnectMQTTClient()
|
||||
{
|
||||
while (!client.connected())
|
||||
{
|
||||
Serial.print("Attempting MQTT connection...");
|
||||
|
||||
if (client.connect(CLIENT_NAME.c_str()))
|
||||
{
|
||||
Serial.println("connected");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("Retying in 5 seconds - failed, rc=");
|
||||
Serial.println(client.state());
|
||||
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This function tests the connection to the MQTT broker and reconnects if it is not connected. It loops all the time it is not connected, and attempts to connect using the unique client name defined in the config header file.
|
||||
|
||||
If the connection fails, it retries after 5 seconds.
|
||||
|
||||
1. Add the following code below the `reconnectMQTTClient` function:
|
||||
|
||||
```cpp
|
||||
void createMQTTClient()
|
||||
{
|
||||
client.setServer(BROKER.c_str(), 1883);
|
||||
reconnectMQTTClient();
|
||||
}
|
||||
```
|
||||
|
||||
This code sets the MQTT broker for the client, as well as setting up the callback when a message is received. It then attempts to connect to the broker.
|
||||
|
||||
1. Call the `createMQTTClient` function in the `setup` function after the WiFi is connected.
|
||||
|
||||
1. Replace the entire `loop` function with the following:
|
||||
|
||||
```cpp
|
||||
void loop()
|
||||
{
|
||||
reconnectMQTTClient();
|
||||
client.loop();
|
||||
|
||||
delay(2000);
|
||||
}
|
||||
```
|
||||
|
||||
This code starts by reconnecting to the MQTT broker. These connections can be broken easily, so it's worth regularly checking and reconnecting if necessary. It then calls the `loop` method on the MQTT client to process any messages that are coming in on the topic subscribed to. This app is single-threaded, so messages cannot be received on a background thread, therefore time on the main thread needs to be allocated to processing any messages that are waiting on the network connection.
|
||||
|
||||
Finally a delay of 2 seconds ensures the light levels are not sent too often and reduces the power consumption of the device.
|
||||
|
||||
1. Upload the code to your Wio Terminal, and use the Serial Monitor to see the device connecting to WiFi and MQTT.
|
||||
|
||||
```output
|
||||
> Executing task: platformio device monitor <
|
||||
|
||||
source /Users/jimbennett/GitHub/IoT-For-Beginners/1-getting-started/lessons/4-connect-internet/code-mqtt/wio-terminal/nightlight/.venv/bin/activate
|
||||
--- Available filters and text transformations: colorize, debug, default, direct, hexlify, log2file, nocontrol, printable, send_on_enter, time
|
||||
--- More details at http://bit.ly/pio-monitor-filters
|
||||
--- Miniterm on /dev/cu.usbmodem1201 9600,8,N,1 ---
|
||||
--- Quit: Ctrl+C | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
|
||||
Connecting to WiFi..
|
||||
Connected!
|
||||
Attempting MQTT connection...connected
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code-mqtt/wio-terminal](code-mqtt/wio-terminal) folder.
|
||||
|
||||
😀 You have successfully connected your device to an MQTT broker.
|
@ -0,0 +1,80 @@
|
||||
# Control your nightlight over the Internet - Wio Terminal
|
||||
|
||||
In this part of the lesson, you will send telemetry with light levels from your Wio Terminal to the MQTT broker.
|
||||
|
||||
## Install the JSON Arduino libraries
|
||||
|
||||
A popular way to send messages over MQTT is using JSON. There is an Arduino library for JSON that makes reading and writing JSON documents easier.
|
||||
|
||||
### Task
|
||||
|
||||
Install the Arduino JSON library.
|
||||
|
||||
1. Open the nightlight project in VS Code.
|
||||
|
||||
1. Add the following as an additional line to the `lib_deps` list in the `platformio.ini` file:
|
||||
|
||||
```ini
|
||||
bblanchon/ArduinoJson @ 6.17.3
|
||||
```
|
||||
|
||||
This imports [ArduinoJson](https://arduinojson.org), an Arduino JSON library.
|
||||
|
||||
## Publish telemetry
|
||||
|
||||
The next step is to create a JSON document with telemetry and send it to the MQTT broker.
|
||||
|
||||
### Task
|
||||
|
||||
Publish telemetry to the MQTT broker.
|
||||
|
||||
1. Add the following code to the bottom of the `config.h` file to define the telemetry topic name for the MQTT broker:
|
||||
|
||||
```cpp
|
||||
const string CLIENT_TELEMETRY_TOPIC = ID + "/telemetry";
|
||||
```
|
||||
|
||||
The `CLIENT_TELEMETRY_TOPIC` is the topic the device will publish light levels to.
|
||||
|
||||
1. Open the `main.cpp` file
|
||||
|
||||
1. Add the following `#include` directive to the top of the file:
|
||||
|
||||
```cpp
|
||||
#include <ArduinoJSON.h>
|
||||
```
|
||||
|
||||
1. Add the following code inside the `loop` function, just before the `delay`:
|
||||
|
||||
```cpp
|
||||
int light = analogRead(WIO_LIGHT);
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
doc["light"] = light;
|
||||
|
||||
string telemetry;
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
serializeJson(obj, telemetry);
|
||||
|
||||
Serial.print("Sending telemetry ");
|
||||
Serial.println(telemetry.c_str());
|
||||
|
||||
client.publish(CLIENT_TELEMETRY_TOPIC.c_str(), telemetry.c_str());
|
||||
```
|
||||
|
||||
This code reads the light level, and creates a JSON document using ArduinoJson containing this level. This is then serialized to a string and published on the telemetry MQTT topic by the MQTT client.
|
||||
|
||||
1. Upload the code to your Wio Terminal, and use the Serial Monitor to see the light levels being sent to the MQTT broker.
|
||||
|
||||
```output
|
||||
Connecting to WiFi..
|
||||
Connected!
|
||||
Attempting MQTT connection...connected
|
||||
Sending telemetry {"light":652}
|
||||
Sending telemetry {"light":612}
|
||||
Sending telemetry {"light":583}
|
||||
```
|
||||
|
||||
> 💁 You can find this code in the [code-telemetry/wio-terminal](code-telemetry/wio-terminal) folder.
|
||||
|
||||
😀 You have successfully sent telemetry from your device.
|
@ -0,0 +1,22 @@
|
||||
# Farming with IoT
|
||||
|
||||
As the population grows, so does the demand on agriculture. The amount of land available doesn't change, but the climate does - giving even more challenges to farmers, especially the 2 billion [subsistence farmers](https://wikipedia.org/wiki/Subsistence_agriculture) who rely on what they grow to be able to eat and feed their families. IoT can help farmers make smarter decisions on what to grow and when to harvest, increase yields, reduce the amount of manual labor, and detect and deal with pests.
|
||||
|
||||
In these 6 lessons you'll learn how to apply the Internet of Things to improve and automate farming.
|
||||
|
||||
> 💁 These lessons will use some cloud resources. If you don't complete all the lessons in this project, make sure you follow the [Clean up your project](lessons/6-keep-your-plant-secure/README.md#clean-up-your-project) step in [lesson 6](lessons/6-keep-your-plant-secure/README.md).
|
||||
|
||||
**Add video of automated plant**
|
||||
|
||||
## Topics
|
||||
|
||||
1. [Predict plant growth with IoT](lessons/1-predict-plant-growth/README.md)
|
||||
1. [Detect soil moisture](lessons/2-detect-soil-moisture/README.md)
|
||||
1. [Automated plant watering](lessons/3-automated-plant-watering/README.md)
|
||||
1. [Migrate your plant to the cloud](lessons/4-migrate-your-plant-to-the-cloud/README.md)
|
||||
1. [Migrate your application logic to the cloud](lessons/5-migrate-application-to-the-cloud/README.md)
|
||||
1. [Keep your plant secure](lessons/6-keep-your-plant-secure/README.md)
|
||||
|
||||
## Credits
|
||||
|
||||
All the lessons were written with ♥️ by [Jim Bennett](https://GitHub.com/JimBobBennett)
|
@ -0,0 +1,269 @@
|
||||
# Predict plant growth with IoT
|
||||
|
||||
Add a sketchnote if possible/appropriate
|
||||
|
||||

|
||||
|
||||
## Pre-lecture quiz
|
||||
|
||||
[Pre-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/9)
|
||||
|
||||
## Introduction
|
||||
|
||||
Plants need certain things to grow - water, carbon dioxide, nutrients, light, and heat. In this lesson, you'll learn how to calculate the growth and maturity rates of plants by measuring the air temperature.
|
||||
|
||||
In this lesson we'll cover:
|
||||
|
||||
* [Digital agriculture](#digital-agriculture)
|
||||
* [Why is temperature important when farming?](#why-is-temperature-important-when-farming)
|
||||
* [Measure ambient temperature](#measure-ambient-temperature)
|
||||
* [Growing degree days (GDD)](#growing-degree-days)
|
||||
* [Calculate GDD using temperature sensor data](#calculate-gdd-using-temperature-sensor-data)
|
||||
|
||||
## Digital agriculture
|
||||
|
||||
Digital Agriculture is transforming how we farm, using tools to collect, store and analyze data from farming. We are currently in a period described as the 'Fourth Industrial Revolution' by the World Economic Forum, and the rise of digital agriculture has been labelled as the 'Fourth Agricultural Revolution', or 'Agriculture 4.0'.
|
||||
|
||||
> 🎓 The term Digital Agriculture also includes the whole 'agriculture value chain', that is the entire journey from farm to table. It includes tracking produce quality as food is shipped and processed, warehouse and e-commerce systems, even tractor rental apps!
|
||||
|
||||
These changes allow farmers to increase yields, use less fertilizers and pesticides, and water more efficiently. Although primarily used in richer nations, sensors and other devices are slowly reducing in price, making them more accessible in developing nations.
|
||||
|
||||
Some techniques enabled by digital agriculture are:
|
||||
|
||||
* Temperature measurement - measuring temperature allows farmers to predict plant growth and maturity.
|
||||
* Automated watering - measuring soil moisture and turning on irrigation systems when the soil is too dry, rather than timed watering. Timed watering can lead to crops being under-watered during a hot, dry spell, or over-watered during rain. By watering only when the soil needs it farmers can optimize their water use.
|
||||
* Pest control - farmers can use cameras on automated robots or drones to check for pests, then apply pesticides only where needed, reducing the amount of pesticides used and reducing pesticide run-off into local water supplies.
|
||||
|
||||
✅ Do some research. What other techniques are used to improve farming yields?
|
||||
|
||||
> 🎓 The term 'Precision Agriculture' is used to define observing, measuring and responding to crops on a per-field basis, or even on parts of a field. This includes measuring water, nutrient and pest levels and responding accurately, such as watering only a small part of a field.
|
||||
|
||||
## Why is temperature important when farming?
|
||||
|
||||
When learning about plants, most students are taught about the necessity of water, light, carbon dioxide (CO<sub>2</sub>) and nutrients. Plants also need warmth to grow - this is why plants bloom in spring as the temperature rises, why snowdrops or daffodils can sprout early due to a short warm spell, and why hothouses and greenhouses are so good at making plants grow.
|
||||
|
||||
> 🎓 Hothouses and greenhouses do a similar job, but with an important difference. Hothouses are heated artificially and allow farmers to control temperatures more accurately, greenhouses rely on the sun for warmth and usually the only control is windows or other openings to let heat out.
|
||||
|
||||
Plants have a base or minimum temperature, optimal temperature, and maximum temperature, all based on daily average temperatures.
|
||||
|
||||
* Base temperature - this is the minimum daily average temperature needed for a plant to grow.
|
||||
* Optimum temperature - this is the best daily average temperature to get the most growth
|
||||
* Maximum temperature - The is the maximum temperature a plant can withstand. Above this the plant will shut down it's growth in an attempt to conserve water and stay alive.
|
||||
|
||||
> 💁 These are average temperatures, averaged over the daily and nightly temperatures. Plants also need different temperatures day and night to help them photosynthesize more efficiently and save energy at night.
|
||||
|
||||
Each species of plant has different values for their base, optimal and maximum. This is why some plants thrive in hot countries, and others in colder countries.
|
||||
|
||||
✅ Do some research. For any plants you have in your garden, school, or local park see if you can find the base temperature.
|
||||
|
||||

|
||||
|
||||
The graph above shows an example growth rate to temperature graph. Up to the base temperature there is no growth. The growth rate increases up to the optimum temperature, then falls after reaching this peak. At the maximum temperature growth stops.
|
||||
|
||||
The shape of this graph varies from plant species to plant species. Some have sharper drop offs above the optimum, some have slower increases from tbe base to the optimum.
|
||||
|
||||
> 💁 For a farmer to get the best growth, they will need to know the three temperature values and understand the shape of the graphs for the plants they are growing.
|
||||
|
||||
If a farmer has control of temperature, for example in a commercial hothouse, then they can optimise for their plants. A commercial hothouse growing tomatoes for example will have the temperature set to around 25°C during the day and 20°C at night to get the fastest growth.
|
||||
|
||||
> 🍅 Combining these temperatures with artificial lights, fertilizers and controlled CO<sub>2</sub> levels means commercial growers can grow and harvest all year round.
|
||||
|
||||
## Measure ambient temperature
|
||||
|
||||
Temperature sensors can be used with IoT devices to measure ambient temperature.
|
||||
|
||||
### Task - measure temperature
|
||||
|
||||
Work through the relevant guide to monitor temperatures using your IoT device:
|
||||
|
||||
* [Arduino - Wio Terminal](wio-terminal-temp.md)
|
||||
* [Single-board computer - Raspberry Pi](pi-temp.md)
|
||||
* [Single-board computer - Virtual device](virtual-device-temp.md)
|
||||
|
||||
## Growing degree days
|
||||
|
||||
Growing degree days (also know as growing degree units) are a way of measuring the growth of plants based off the temperature. Assuming a plant has enough water, nutrients and CO<sub>2</sub>, the temperature determines the growth rate.
|
||||
|
||||
Growing degree days, or GDD are calculated per day as the average temperature in Celsius for a day above the plants base temperature. Each plant needs a certain number of GDD to grow, flower or produce and mature a crop. The more GDD each day, the faster the plant will grow.
|
||||
|
||||
> 🇺🇸 For Americans, growing degree days can also be calculated using Fahrenheit. 5 GDD<sup>C</sup> (growing degree days in Celsius) is the equivalent of 9 GDD<sup>F</sup> (growing degree days in Fahrenheit).
|
||||
|
||||
The full formula for GDD is a little complicated, but there is a simplified equation that is often used as a good approximation:
|
||||
|
||||

|
||||
|
||||
* **GDD** - this is the number of growing degree days
|
||||
* **T<sub>max</sub>** - this is the daily maximum temperature in degrees Celsius
|
||||
* **T<sub>min</sub>** - this is the daily minimum temperature in degrees Celsius
|
||||
* **T<sub>base</sub>** - this is the plants base temperature in degrees Celsius
|
||||
|
||||
> 💁 There are variations that deal with T<sub>max</sub> above 30°C or T<sub>min</sub> below T<sub>base</sub>, but we'll ignore these for now.
|
||||
|
||||
### Example - Corn/Maize 🌽
|
||||
|
||||
Depending on the variety, corn (or maize) needs between 800 and 2,700 GDD to mature, with a base temperature of 10°C.
|
||||
|
||||
On the first day above the base temperature, the following temperatures were measured:
|
||||
|
||||
| Measurement | Temp °C |
|
||||
| :---------- | :-----: |
|
||||
| Maximum | 16 |
|
||||
| Minimum | 12 |
|
||||
|
||||
Plugging these numbers in to our calculation:
|
||||
|
||||
* T<sub>max</sub> = 16
|
||||
* T<sub>min</sub> = 12
|
||||
* T<sub>base</sub> = 10
|
||||
|
||||
This gives a calculation of:
|
||||
|
||||

|
||||
|
||||
The corn received 4 GDD on that day. Assuming a corn variety that needs 800 GDD days to mature, it will need another 796 GDD to reach maturity.
|
||||
|
||||
✅ Do some research. For any plants you have in your garden, school, or local park see if you can find the number of GDD required to reach maturity or produce crops.
|
||||
|
||||
## Calculate GDD using temperature sensor data
|
||||
|
||||
Plants don't grow on fixed dates - for example you can't plant a seed and know that the plant will bear fruit exactly 100 days later. Instead as a farmer you can have a rough idea how long a plant takes to grow, then you would check daily to see when the crops were ready.
|
||||
|
||||
This has a huge labour impact on a large farm, and risks the farmer missing crops that are ready unexpectedly early. By measuring temperatures, the farmer can calculate the GDD a plant has received, allowing them to only check close to the expected maturity.
|
||||
|
||||
By gathering temperature data using an IoT device, a farmer can automatically be notified when plants are close to maturity. A typical architecture for this is to have the IoT devices measure temperature, then publish this telemetry data over the Internet using something like MQTT. Server code then listens to this data and saves it somewhere, such as to a database. This means the data can then be analyzed later, such as a nightly job to calculate the GDD for the day, total up the GDD for each crop so far and alert if a plant is close to maturity.
|
||||
|
||||

|
||||
|
||||
***Telemetry data is sent to a server and then saved to a database. database by Icons Bazaar - from the [Noun Project](https://thenounproject.com)***
|
||||
|
||||
The server code can also augment the data by adding extra information. For example, the IoT device can publish an identifier to indicate which device it is, and the sever code can use this to look up the location of the device, and what crops it is monitoring. It can also add basic data like the current time as some IoT devices don't have the necessary hardware to keep track of an accurate time, or require additional code to read the current time over the Internet.
|
||||
|
||||
✅ Why do you think different fields might have different temperatures?
|
||||
|
||||
### Task - publish temperature information
|
||||
|
||||
Work through the relevant guide to publish temperature data over MQTT using your IoT device so it can be analyzed later:
|
||||
|
||||
* [Arduino - Wio Terminal](wio-terminal-temp-publish.md)
|
||||
* [Single-board computer - Raspberry Pi/Virtual IoT device](single-board-computer-temp-publish.md)
|
||||
|
||||
### Task - capture and store the temperature information
|
||||
|
||||
Once the IoT device is publishing telemetry, the server code can be written to subscribe to this data and store it. Rather than save it to a database, the server code will save it to a Comma Separated Values (CSV) file. CSV files store data as rows of values as text with each value separated by a comma, and each record on a new line. They are a convenient, human-readable and well supported way to save data as a file.
|
||||
|
||||
The CSV file will have two columns - *date* and *temperature*. The *date* column is set as the current date and time that the message was received by the server, the *temperature* comes from the telemetry message.
|
||||
|
||||
1. Repeat the steps in lesson 4 to create server code to subscribe to telemetry. You don't need to add code to publish commands.
|
||||
|
||||
The steps for this are:
|
||||
|
||||
* Configure and activate a Python Virtual Environment
|
||||
|
||||
* Install the paho-mqtt pip package
|
||||
|
||||
* Write the code to listen for MQTT messages published on the telemetry topic
|
||||
|
||||
> ⚠️ You can refer to [the instructions in lesson 4 for creating a Python app to receive telemetry if needed](../../../1-getting-started/lessons/4-connect-internet/README.md#receive-telemetry-from-the-mqtt-broker).
|
||||
|
||||
Name the folder for this project `temperature-sensor-server`.
|
||||
|
||||
1. Make sure the `client_name` reflects this project:
|
||||
|
||||
```cpp
|
||||
client_name = id + 'temperature_sensor_server'
|
||||
```
|
||||
|
||||
1. Add the following imports to the top of the file, below the existing imports:
|
||||
|
||||
```python
|
||||
from os import path
|
||||
import csv
|
||||
from datetime import datetime
|
||||
```
|
||||
|
||||
This imports a library for reading files, a library to interact with CSV files, and a library to help with dates and times.
|
||||
|
||||
1. Add the following code before the `handle_telemetry` function:
|
||||
|
||||
```python
|
||||
temperature_file_name = 'temperature.csv'
|
||||
fieldnames = ['date', 'temperature']
|
||||
|
||||
if not path.exists(temperature_file_name):
|
||||
with open(temperature_file_name, mode='w') as csv_file:
|
||||
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
```
|
||||
|
||||
This code declares some constants for the name of the file to write to, and the name of the column headers for the CSV file. The first row of a CSV file traditionally contains column headers separated by commas.
|
||||
|
||||
The code then checks to see if the CSV file already exists. If it doesn't exist, it is created with the column headers on the first row.
|
||||
|
||||
1. Add the following code to the end of the `handle_telemetry` function:
|
||||
|
||||
```python
|
||||
with open(temperature_file_name, mode='a') as temperature_file:
|
||||
temperature_writer = csv.DictWriter(temperature_file, fieldnames=fieldnames)
|
||||
temperature_writer.writerow({'date' : datetime.now().astimezone().replace(microsecond=0).isoformat(), 'temperature' : payload['temperature']})
|
||||
```
|
||||
|
||||
This code opens the CSV file, then appends a new row on the end. The row has the current data and time formatted into a human-readable format, followed by the temperature received from the IoT device. The data is stored in [ISO 8601 format](https://wikipedia.org/wiki/ISO_8601) with the timezone, but without microseconds.
|
||||
|
||||
1. Run this code in the same way as before, making sure your IoT device is sending data. A CSV file called `temperature.csv` will be created in the same folder. If you view it you will see date/times and temperature measurements:
|
||||
|
||||
```output
|
||||
date,temperature
|
||||
2021-04-19T17:21:36-07:00,25
|
||||
2021-04-19T17:31:36-07:00,24
|
||||
2021-04-19T17:41:36-07:00,25
|
||||
```
|
||||
|
||||
1. Run this code for a while to capture data. Ideally you should run this for a an entire day to gather enough data for GDD calculations.
|
||||
|
||||
> 💁 If you want to run this for an entire day, then you need to make sure the computer your server code is running on won't go to sleep, either by changing your power settings, or running something like [this keep system active Python script](https://github.com/jaqsparow/keep-system-active).
|
||||
|
||||
> 💁 You can find this code in the [code-server/server](code-server/server) folder.
|
||||
|
||||
### Task - calculate GDD using the stored data
|
||||
|
||||
Once the server has captured temperature data, the GDD for a plant can be calculated.
|
||||
|
||||
The steps to do this manually are:
|
||||
|
||||
1. Find the base temperature for the plant. For example, for strawberries the base temperature is 10°C.
|
||||
|
||||
1. From the `temperature.csv`, find the highest and lowest temperatures for the day
|
||||
|
||||
1. Use the GDD calculation given earlier to calculate GDD
|
||||
|
||||
For example, if the highest temperature for the day is 25°C, and the lowest is 12°C:
|
||||
|
||||

|
||||
|
||||
* 25 + 12 = 37
|
||||
* 37 / 2 = 18.5
|
||||
* 18.5 - 10 = 8.5
|
||||
|
||||
Therefore the strawberries have received **8.5** GDD. Strawberries need about 250 GDD to bear fruit, so still a while to go.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Challenge
|
||||
|
||||
Plants need more than heat to grow. What other things are needed?
|
||||
|
||||
For these, find if there are sensors that can measure them. What about actuators to control these levels? How would you put together one or more IoT devices to optimize plant growth?
|
||||
|
||||
## Post-lecture quiz
|
||||
|
||||
[Post-lecture quiz](https://brave-island-0b7c7f50f.azurestaticapps.net/quiz/10)
|
||||
|
||||
## Review & Self Study
|
||||
|
||||
Read more on digital agriculture on the [Digital Agriculture Wikipedia page](https://wikipedia.org/wiki/Digital_agriculture). Also read more about precision agriculture the [Precision Agriculture Wikipedia page](https://wikipedia.org/wiki/Precision_agriculture).
|
||||
|
||||
The full growing degree days calculation is more complicated than the simplified one given here. Read more about the more complicated equation and how to deal with temperatures below the baseline on the [Growing Degree Day Wikipedia page](https://wikipedia.org/wiki/Growing_degree-day).
|
||||
|
||||
## Assignment
|
||||
|
||||
[Visualize GDD data using a Jupyter Notebook](assignment.md)
|
@ -0,0 +1,43 @@
|
||||
# Visualize GDD data using a Jupyter Notebook
|
||||
|
||||
## Instructions
|
||||
|
||||
In this lesson you gathered GDD data using an IoT sensor. To get good GDD data, you need to gather data for multiple days. To help visualize temperature data and calculate GDD you can use tools like [Jupyter Notebooks](https://jupyter.org) to analyze the data.
|
||||
|
||||
Start by gathering data for a few days. You will need to ensure your server code is running all the time your IoT device is running, either by adjusting your power management settings or running something like [this keep system active Python script](https://github.com/jaqsparow/keep-system-active).
|
||||
|
||||
Once you have temperature data, you can use a Jupyter Notebook in this repo to visualize it and calculate GDD. Jupyter notebooks mix code and instructions in blocks called *cells*, often code in Python. You can read the instructions, then run each block of code block by block. You can also edit the code. In this notebook for example, you can edit the base temperature used to calculate the GDD for your plant.
|
||||
|
||||
1. Create a folder called `gdd-calculation`
|
||||
|
||||
1. Download the [gdd.ipynb](./code-notebook/gdd.ipynb) file and copy it into the `gdd-calculation` folder.
|
||||
|
||||
1. Copy the `temperature.csv` file created by the MQTT server
|
||||
|
||||
1. Create a new Python virtual environment in the `gdd-calculation` folder.
|
||||
|
||||
1. Install some pip packages for Jupyter notebooks, along with libraries needed to manage and plot the data:
|
||||
|
||||
```sh
|
||||
pip install -U pip
|
||||
pip install pandas
|
||||
pip install matplotlib
|
||||
pip install jupyter
|
||||
```
|
||||
|
||||
1. Run the notebook in Jupyter:
|
||||
|
||||
```sh
|
||||
jupyter notebook gdd.ipynb
|
||||
```
|
||||
|
||||
Jupyter will start up and open the notebook in your browser. Work through the instructions in the notebook to visualize the temperatures measured, and calculate the growing degree days.
|
||||
|
||||

|
||||
|
||||
## Rubric
|
||||
|
||||
| Criteria | Exemplary | Adequate | Needs Improvement |
|
||||
| -------- | --------- | -------- | ----------------- |
|
||||
| Capture data | Capture at least 2 complete days of data | Capture at least 1 complete day of data | Capture some data |
|
||||
| Calculate GDD | Successfully run the notebook and calculate GDD | Successfully run the notebook | Not able to run the notebook |
|
@ -0,0 +1,156 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Growing Degree Days\n",
|
||||
"\n",
|
||||
"This notebook loads temperature data saved in a CSV file, and analyzes it. It plots the temperatures, shows the highest and lowest value for each day, and calculates the GDD.\n",
|
||||
"\n",
|
||||
"To use this notebook:\n",
|
||||
"\n",
|
||||
"* Copy the `temperature.csv` file into the same folder as this notebook\n",
|
||||
"* Run all the cells using the **▶︎ Run** button above. This will run the selected cell, then move to the next one."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In the cell below, set `base_temperature` to the base temperature of the plant."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"base_temperature = 10"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The CSV file now needs to be loaded, using pandas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"# Read the temperature CSV file\n",
|
||||
"df = pd.read_csv('temperature.csv')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The temperature can now be plotted on a graph."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"plt.figure(figsize=(20, 10))\n",
|
||||
"plt.plot(df['date'], df['temperature'])\n",
|
||||
"plt.xticks(rotation='vertical');"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Once the data has been read it can be grouped by the `date` column, and the minimum and maximum temperatures extracted for each date."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Convert datetimes to pure dates so we can group by the date\n",
|
||||
"df['date'] = pd.to_datetime(df['date']).dt.date\n",
|
||||
"\n",
|
||||
"# Group the data by date so it can be analyzed by date\n",
|
||||
"data_by_date = df.groupby('date')\n",
|
||||
"\n",
|
||||
"# Get the minimum and maximum temperatures for each date\n",
|
||||
"min_by_date = data_by_date.min()\n",
|
||||
"max_by_date = data_by_date.max()\n",
|
||||
"\n",
|
||||
"# Join the min and max temperatures into one dataframe and flatten it\n",
|
||||
"min_max_by_date = min_by_date.join(max_by_date, on='date', lsuffix='_min', rsuffix='_max')\n",
|
||||
"min_max_by_date = min_max_by_date.reset_index()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The GDD can be calculated using the standard GDD equation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def calculate_gdd(row):\n",
|
||||
" return ((row['temperature_max'] + row['temperature_min']) / 2) - base_temperature\n",
|
||||
"\n",
|
||||
"# Calculate the GDD for each row\n",
|
||||
"min_max_by_date['gdd'] = min_max_by_date.apply (lambda row: calculate_gdd(row), axis=1)\n",
|
||||
"\n",
|
||||
"# Print the results\n",
|
||||
"print(min_max_by_date[['date', 'gdd']].to_string(index=False))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
},
|
||||
"metadata": {
|
||||
"interpreter": {
|
||||
"hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
import time
|
||||
from seeed_dht import DHT
|
||||
import paho.mqtt.client as mqtt
|
||||
import json
|
||||
|
||||
sensor = DHT("11", 5)
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
client_name = id + 'temperature_sensor_client'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
print("MQTT connected!")
|
||||
|
||||
while True:
|
||||
_, temp = sensor.read()
|
||||
telemetry = json.dumps({'temperature' : temp})
|
||||
|
||||
print("Sending telemetry ", telemetry)
|
||||
|
||||
mqtt_client.publish(client_telemetry_topic, telemetry)
|
||||
|
||||
time.sleep(10 * 60)
|
@ -0,0 +1,31 @@
|
||||
from counterfit_connection import CounterFitConnection
|
||||
CounterFitConnection.init('127.0.0.1', 5000)
|
||||
|
||||
import time
|
||||
from counterfit_shims_seeed_python_dht import DHT
|
||||
import paho.mqtt.client as mqtt
|
||||
import json
|
||||
|
||||
sensor = DHT("11", 5)
|
||||
|
||||
id = '<ID>'
|
||||
|
||||
client_telemetry_topic = id + '/telemetry'
|
||||
client_name = id + 'temperature_sensor_client'
|
||||
|
||||
mqtt_client = mqtt.Client(client_name)
|
||||
mqtt_client.connect('test.mosquitto.org')
|
||||
|
||||
mqtt_client.loop_start()
|
||||
|
||||
print("MQTT connected!")
|
||||
|
||||
while True:
|
||||
_, temp = sensor.read()
|
||||
telemetry = json.dumps({'temperature' : temp})
|
||||
|
||||
print("Sending telemetry ", telemetry)
|
||||
|
||||
mqtt_client.publish(client_telemetry_topic, telemetry)
|
||||
|
||||
time.sleep(10 * 60)
|
@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
@ -0,0 +1,46 @@
|
||||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
@ -0,0 +1,23 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:seeed_wio_terminal]
|
||||
platform = atmelsam
|
||||
board = seeed_wio_terminal
|
||||
framework = arduino
|
||||
lib_deps =
|
||||
seeed-studio/Grove Temperature And Humidity Sensor @ 1.0.1
|
||||
knolleary/PubSubClient @ 2.8
|
||||
bblanchon/ArduinoJson @ 6.17.3
|
||||
seeed-studio/Seeed Arduino rpcWiFi @ 1.0.3
|
||||
seeed-studio/Seeed Arduino FS @ 2.0.2
|
||||
seeed-studio/Seeed Arduino SFUD @ 2.0.1
|
||||
seeed-studio/Seeed Arduino rpcUnified @ 2.1.3
|
||||
seeed-studio/Seeed_Arduino_mbedtls @ 3.0.1
|
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// WiFi credentials
|
||||
const char *SSID = "<SSID>";
|
||||
const char *PASSWORD = "<PASSWORD>";
|
||||
|
||||
// MQTT settings
|
||||
const string ID = "<ID>";
|
||||
|
||||
const string BROKER = "test.mosquitto.org";
|
||||
const string CLIENT_NAME = ID + "temperature_sensor_client";
|
||||
|
||||
const string CLIENT_TELEMETRY_TOPIC = ID + "/telemetry";
|
@ -0,0 +1,89 @@
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <DHT.h>
|
||||
#include <PubSubClient.h>
|
||||
#include <rpcWiFi.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
DHT dht(D0, DHT11);
|
||||
|
||||
void connectWiFi()
|
||||
{
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
Serial.println("Connecting to WiFi..");
|
||||
WiFi.begin(SSID, PASSWORD);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
Serial.println("Connected!");
|
||||
}
|
||||
|
||||
WiFiClient wioClient;
|
||||
PubSubClient client(wioClient);
|
||||
|
||||
void reconnectMQTTClient()
|
||||
{
|
||||
while (!client.connected())
|
||||
{
|
||||
Serial.print("Attempting MQTT connection...");
|
||||
|
||||
if (client.connect(CLIENT_NAME.c_str()))
|
||||
{
|
||||
Serial.println("connected");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("Retying in 5 seconds - failed, rc=");
|
||||
Serial.println(client.state());
|
||||
|
||||
delay(5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void createMQTTClient()
|
||||
{
|
||||
client.setServer(BROKER.c_str(), 1883);
|
||||
reconnectMQTTClient();
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
while (!Serial)
|
||||
; // Wait for Serial to be ready
|
||||
|
||||
delay(1000);
|
||||
|
||||
dht.begin();
|
||||
|
||||
connectWiFi();
|
||||
createMQTTClient();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
reconnectMQTTClient();
|
||||
client.loop();
|
||||
|
||||
float temp_hum_val[2] = {0};
|
||||
dht.readTempAndHumidity(temp_hum_val);
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
doc["temperature"] = temp_hum_val[1];
|
||||
|
||||
string telemetry;
|
||||
JsonObject obj = doc.as<JsonObject>();
|
||||
serializeJson(obj, telemetry);
|
||||
|
||||
Serial.print("Sending telemetry ");
|
||||
Serial.println(telemetry.c_str());
|
||||
|
||||
client.publish(CLIENT_TELEMETRY_TOPIC.c_str(), telemetry.c_str());
|
||||
|
||||
delay(10 * 60 * 1000);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue