An open-source MicroPython based OS for ESP microcontroller variants (ESP8266, ESP32). It enables you to focus on your actual project by providing ready-made functionality for tedious stuff.
- Handles connections with known Wi-Fi networks according to user-defined priority
- Detects single or any number of taps on microcontroller buttons and allows execution of any code after that
- Allows the user to take control of the on-board LEDs and blink them with any pattern and delay
- Automated installation on the board
- Filesystem formatter cleans up your board - no need to reflash it
- Send (Insta)Push notifications to your mobile phone straight from your microcontroller
- Update a Dynamic DNS service (DuckDNS) so that your microcontroller is always available online
- Can be configured for (potentially) any MicroPython enabled microcontroller (out of the box support for
NodeMCU
) - Simple logging functionality
- Ability to read .properties files for configuration
- Memory manager that periodically calls garbage collector
- Intended for use in both commercial and open-source projects.
- Extend your on-board memory by using the Stepper mechanism!
- Drive DHT11 and DHT22 (both sensors for humidity and temperature) using cool wrappers for the MicroPython drivers
- Drive the BMP180 sensor (temperature, pressure, altitude)
- Drive any Analog Sensor (e.g. Rain sensor, Soil humidity sensor etc)
- Drive SSD1306 OLED screens
Profiles (i.e. ready-made profiles that provide a specific functionality set provided that you have done all the required hardware wiring/soldering)
- Plant Monitor (monitors soil humidity)
- Weather Station (in progress...)
Github issues list/bugtracker: https://github.com/idimitrakopoulos/illuminOS/issues Micropython www.micropython.org
Clone the git repository in any local directory by typing the following:
$ git clone https://github.com/idimitrakopoulos/illuminOS
Now you need to install it to your board. To do this first ensure you have the latest MicroPython firmware installed and that your board is plugged in to your computer via USB.
I use espedite
which is a smart code uploader and works really well with illuminOS. To get it type:
$ git clone https://github.com/idimitrakopoulos/espedite
After cloning is complete use the following commands to install illuminOS (assuming the device is /dev/ttyUSB0
):
$ cd illuminOS
$ ../espedite/espedite.py -i -C -v -s espedite.skip -d /dev/ttyUSB0 -c
This will compile all micropython source files and install them to your board.
You can skip compilation by removing the -C flag but it's not recommended because it will save you lot's of runtime memory. Again you should make sure you have the latest micropython firmware on your board if you want to use the -C feature.
Use the following command to uninstall illuminOS (assuming the device is /dev/ttyUSB0
):
$ cd illuminOS
$ ../espedite/espedite.py -u
Both bootstrap files main.py
and boot.py
are intentionally left empty so that you can add your own code. You'll see commented out code to get you started.
You may use ready-made programs called profiles. Profiles are located under the profile folder and when used they are copied using espedite to the root of the board's filesystem effectively overwriting the empty main.py file. This give you ready made functionality that can work if you have the correct hardware and wiring installed on the board.
For example the plant_monitor profile offers functionality to turn an ESP8266 board into a plant monitor. Install it using
$ cd illuminOS
$ ../espedite/espedite.py -i -C -v -s espedite.skip -d /dev/ttyUSB0 -p plant_monitor -c
The user is free to utilize the functionality offered by illuminOS freely and at any point. It certainly makes sense however, to play with some of the examples below.
illuminOS offers a stepper that enables you to extend the things a single ESP board can do. Basically it allows you to segment your code in steps and then reboot. You may write down your state (variables etc) between reboots and of course your step ID. Rebooting clears all used memory allowing you to take your ESP even further! On board reboot the Stepper identifies the step reads the state and continues with additional functionality.
Sample step scenario:
- Import all sensor drivers and get your readings
- Reboot & write readings to local file
- Read readings from local file
- Connect to WiFi
- Upload readings (anywhere) using a JSON call
- Remove local file
- Reboot
This will start again from the top. You can customize and run any number of steps. This coupled with the compile feature when uploading your code allows you to not worry about memory consumption 99% of the times.
An implementation using Stepper can be found in profile/plant_monitor/main.py
illuminOS is open enough to allow the configuration and control of any ESP based microcontroller. At this point only NodeMCU has been configured by the author but other controllers can be contributed by users.
To do this a new board class must be created that inherits from hw.Board.
e.g. hw/board/NodeMCU.py
In this class board related configuration can be mapped and Board functions invoked. The concept is to abstract hardware mapping as much as possible from functionality.
Simply edit conf/network.properties
with WiFi SSID and password as shown below
[wifi]
mynetwork = "abcdef"
worknet = "2334d"
Then in main.py
the following code must be copied. This will scan for known SSIDs as per the configuration above and connect to the first preferred network
from hw.board.NodeMCU import NodeMCU
# Instantiate our board
board = NodeMCU()
# Find preferred wifi
preferred_wifi = determine_preferred_wifi(load_properties("conf/network.properties"), board.scan_wifi())
# Get IP
ip = board.connect_to_wifi(preferred_wifi["ssid"], preferred_wifi["password"], 10)
To listen for clicks on the Flash button of your board, place the following snippet in your main.py
. This places a polling timer which anticipates button clicks. Upon first click it very briefly waits for another click and then registers either a single or a double click.
Following this event you could execute any code required by your project on single or double click (you need to specify this function in lib.toolkit
module).
For the Flash button use
from hw.board.NodeMCU import NodeMCU
# Instantiate our board
board = NodeMCU()
# Listen for events on FLASH button and run "hello_world" function on single and double click
board.get_flash_button_events("hello_world", "hello_world")
And for the User button use
# Listen for events on USER button and run "hello_world" function on single and double click
board.get_user_button_events("hello_world", "hello_world")
You can make the on-board LEDs flash as per requirement by using the following command.
from hw.board.NodeMCU import NodeMCU
# Instantiate our board
board = NodeMCU()
# Blink BLUE LED 5 times with 0.5 sec delay
board.blink_blue_led(5, 0.5)
You can recursively wipe files and folders from your microcontroller using this function.
from hw.board.NodeMCU import NodeMCU
# Instantiate our board
board = NodeMCU()
# Request format - this will wipe all the filesystem
board.format()
You can use the InstaPush service to send push notifications to your mobile phone.
- Go to the Instapush website and create an account.
- Download the Instapush app on your phone and login there as well
- Once inside go to dashboard and create a new "application", give any name you like
- In your new application create a new event
- For the sake of this example name it "send_ip" (it can be anything you choose really)
- Add a tracker called "ip"
- Formulate your message as such "Hello, my IP address is {ip}"
- Save it and make note of your app ID and app Secret
- Add the following to your code
from lib.toolkit import sendInstapushNotification
r = sendInstapushNotification("57f65af3455ag7848a96876hjf077c3", "ea456d8c303be4shhg56669339ca43b8", "send_ip", {'ip': ip})
You can use the InstaPush service to send push notifications to your mobile phone.
- Go to the DuckDNS website and create an account.
- Once inside go to dashboard and create a new "domain", give any name you like
- Save it and make note of your token id
- Add the following to your code
from lib.toolkit import update_duck_dns
# Update DuckDNS service
update_duck_dns("mydomain", "mytoken", "192.168.0.10")
In case you want to provide configuration using .properties files you can use the illuminOS method load_properties
from lib.toolkit import load_properties
load_properties("conf/my.properties")
Garbage collection is better performed before it's needed, the memory manager periodically runs and collects garbage plus it reports if memory is low
from hw.board.NodeMCU import NodeMCU
# Instantiate our board
board = NodeMCU()
# Memory collection and reporting will occur every 10 sec
board.start_memory_manager(10000)
# Or you can run memory manager ad hoc
board.mem_cleanup()
A simple logging functionality exists
import gc
from lib.Logger import Logger
log = Logger()
log.info("Hello!")
log.error("Critical Issue!!")
log.debug("Free memory: " + str(gc.free_mem()))
Drive the DHT11 and DHT22 sensors using cool wrappers for the Micropython drivers
from hw.sensor.DHT import DHT, DHTType, TemperatureUnit
# Instantiate our sensor
d = DHT(DHTType.DHT11, 10)
# Get temperature in Celsius
d.get_temperature()
# Get temperature in Fahrenheit
d.get_temperature(TemperatureUnit.FAHRENHEIT)
# Get temperature numeric in Celsius
d.get_temperature(TemperatureUnit.CELSIUS, False)
# Get temperature numeric in Fahrenheit
d.get_temperature(TemperatureUnit.FAHRENHEIT, False)
Drive Temperature/Pressure/Altitude sensor (BMP180 or BMP280)
from hw.sensor.BMP import BMP, BMPType, TemperatureUnit, PressureUnit, AltitudeUnit
# Instantiate our sensor
s = BMP(BMPType.BMP180, 2, 0)
# Get temperature in Celsius
s.get_temperature()
# Get temperature in Fahrenheit
s.get_temperature(TemperatureUnit.FAHRENHEIT)
# Get temperature numeric in Celsius
s.get_temperature(TemperatureUnit.CELSIUS, False)
# Get temperature numeric in Fahrenheit
s.get_temperature(TemperatureUnit.FAHRENHEIT, False)
# Get altitude in meters
s.get_altitude(AltitudeUnit.METERS)
# Get pressure in hectopascals
s.get_pressure(PressureUnit.HECTOPASCAL)
Drive the ssd1306 OLED screen
from hw.screen.SSD1306 import SSD1306
from hw.screen.Screen import ConnectionType
import machine
bus = machine.I2C(machine.Pin(4), machine.Pin(5))
oled = SSD1306(ConnectionType.I2C, bus)
oled.text("hello world")
from hw.sensor.AnalogSensor import AnalogSensor
soil_sensor = AnalogSensor(0, 1024, 364) # 364 is submerged in water and 1024 is dry
soil_sensor.get_value()
The content of this project itself is licensed under the Creative Commons Attribution 3.0 license, and the underlying source code used to format and display that content is licensed under the MIT license.
Enjoy!
Iason D.