Index
NodeMCU Documentation
NodeMCU is an open source Lua based firmware for the ESP8266 WiFi SOC from Espressif and uses an on-module flash-based SPIFFS file system. NodeMCU is implemented in C and is layered on the Espressif NON-OS SDK.
The firmware was initially developed as is a companion project to the popular ESP8266-based NodeMCU development modules, but the project is now community-supported, and the firmware can now be run on _any_ ESP module.
ā Getting Started
Programming Model
The NodeMCU programming model is similar to that of Node.js, only in Lua. It is asynchronous and event-driven. Many functions, therefore, have parameters for callback functions. To give you an idea what a NodeMCU program looks like study the short snippets below. For more extensive examples have a look at the
/lua_examples folder in the repository on GitHub.-- a simple HTTP server
srv = net.createServer(net.TCP)
srv:listen(80, function(conn)
conn:on("receive", function(sck, payload)
print(payload)
sck:send("HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n<h1> Hello, NodeMCU. </h1>")
end)
conn:on("sent", function(sck) sck:close() end)
end)-- connect to WiFi access point (DO NOT save config to flash)
wifi.setmode(wifi.STATION)
station_cfg={}
station_cfg.ssid = "SSID"
station_cfg.pwd = "password"
station_cfg.save = false
wifi.sta.config(station_cfg)-- register event callbacks for WiFi events
wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, function(T)
print("\n\tSTA - CONNECTED".."\n\tSSID: "..T.SSID.."\n\tBSSID: "..
T.BSSID.."\n\tChannel: "..T.channel)
end)-- manipulate hardware like with Arduino
pin = 1
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)
print(gpio.read(pin))ā Getting Started
Lua Flash Store (LFS)
In September 2018 support for a Lua Flash Store (LFS) was introduced. LFS allows Lua code and its associated constant data to be executed directly out of flash-memory; just as the firmware itself is executed. This now enables NodeMCU developers to create Lua applications with up to 256Kb Lua code and read-only constants executing out of flash. All of the RAM is available for read-write data!
Releases
This project uses two main branches, release and dev. dev is actively worked on and it's also where PRs should be created against. release thus can be considered "stable" even though there are no automated regression tests. The goal is to merge back to release roughly every 2 months. Depending on the current "heat" (issues, PRs) we accept changes to dev for 5-6 weeks and then hold back for 2-3 weeks before the next snap is completed.
A new tag is created every time dev is merged back to release branch. They are listed in the releases section on GitHub. Tag names follow the <SDK-version>-release_yyyymmdd pattern.
Up-To-Date Documentation
At the moment the only up-to-date documentation maintained by the current NodeMCU team is in English. It is part of the source code repository (
/docs subfolder) and kept in sync with the code.---
Getting Started
Getting Started aka NodeMCU Quick Start
The basic process to get started with NodeMCU consists of the following three steps.
1. Build the firmware with the modules you need
1. Flash the firmware to the chip
1. Upload code to the device.
You will typically do steps 1 and 2 only once, but then repeat step 3 as you develop your application. If your application outgrows the limited on-chip RAM then you can use the Lua Flash Store (LFS) to move your Lua code into flash memory, freeing a lot more RAM for variable data. This is why it is a good idea to enable LFS for step 1 if you are developing a larger application. As documented below there is a different approach to uploading Lua code.
!!! caution
For each of the tasks you have a number of choices with regards to tooling and depending on the OS you are on. The colored boxes represent an opinionated path to start your journey - the quickest way to success so to speak. Feel free to follow the links above to get more detailed information.
Task and OS selector
<table id="gs">
<tr>
<th>Task \ OS</th>
<th>Windows<div class="icon windowsIcon"></span></th>
<th>macOS<div class="icon appleIcon"></th>
<th>Linux<div class="icon linuxIcon"></th>
</tr>
<tr>
<th rowspan="3">Build firmware</th>
<td class="select"><a href="#cloud-builder">cloud builder</a></td>
<td class="select"><a href="#cloud-builder">cloud builder</a></td>
<td class="select"><a href="#cloud-builder">cloud builder</a></td>
</tr>
<tr>
<td><a href="#docker">Docker</a></td>
<td><a href="#docker">Docker</a></td>
<td><a href="#docker">Docker</a></td>
</tr>
<tr>
<td></td>
<td></td>
<td>native</td>
</tr>
<tr>
<th rowspan="2">Flash firmware</th>
<td class="select"><a href="#nodemcu-pyflasher">NodeMCU PyFlasher</a></td>
<td class="select"><a href="#nodemcu-pyflasher">NodeMCU PyFlasher</a></td>
<td></td>
</tr>
<tr>
<td><a href="#esptoolpy">esptool.py</a></td>
<td><a href="#esptoolpy">esptool.py</a></td>
<td class="select"><a href="#esptoolpy">esptool.py</a></td>
</tr>
<tr>
<th rowspan="2">Upload code</th>
<td class="select"><a href="#esplorer">ESPlorer (Java)</a></td>
<td><a href="#esplorer">ESPlorer (Java)</a></td>
<td><a href="#esplorer">ESPlorer (Java)</a></td>
</tr>
<tr>
<td><a href="#nodemcu-tool">NodeMCU-Tool (Node.js)</a></td>
<td class="select"><a href="#nodemcu-tool">NodeMCU-Tool (Node.js)</a></td>
<td class="select"><a href="#nodemcu-tool">NodeMCU-Tool (Node.js)</a></td>
</tr>
<t>
<th colspan="4">LFS tasks below</th>
</tr>
<tr>
<th rowspan="3">Build LFS<br>enabled firmware</th>
<td class="select"><a href="#for-lfs">cloud builder</a></td>
<td class="select"><a href="#for-lfs">cloud builder</a></td>
<td class="select"><a href="#for-lfs">cloud builder</a></td>
</tr>
<tr>
<td><a href="#for-lfs_1">Docker</a></td>
<td><a href="#for-lfs_1">Docker</a></td>
<td><a href="#for-lfs_1">Docker</a></td>
</tr>
<tr>
<td></td>
<td></td>
<td>native</td>
</tr>
<tr>
<th rowspan="3">Build luac.cross</th>
<td>not needed if you use Terry's webservice or Docker to later compile LFS image</td>
<td>not needed if you use Terry's webservice or Docker to later compile LFS image</td>
<td>not needed if you use Terry's webservice or Docker to later compile LFS image</td>
</tr>
<tr>
<td><a href="#windows">native</a></td>
<td><a href="#macos">native</a></td>
<td><a href="#linux">native</a></td>
</tr>
<tr>
<td><a href="https://github.com/nodemcu/nodemcu-firmware/releases">download from release</a></td>
<td></td>
<td></td>
</tr>
<tr>
<th rowspan="3">Compile Lua into<br>LFS image</th>
<td class="select"><a href="#terrys-lfs-lua-cross-compile-web-service">webservice</a></td>
<td><a href="#terrys-lfs-lua-cross-compile-web-service">webservice</a></td>
<td><a href="#terrys-lfs-lua-cross-compile-web-service">webservice</a></td>
</tr>
<tr>
<td><a href="#docker_1">Docker</a></td>
<td><a href="#docker_1">Docker</a></td>
<td><a href="#docker_1">Docker</a></td>
</tr>
<tr>
<td><a href="#native-on-os">native</a></td>
<td><a href="#native-on-os">native</a></td>
<td><a href="#native-on-os">native</a></td>
</tr>
<tr>
<th>Upload LFS image</th>
<td class="select"><a href="#upload-lfs-image">generic</a></td>
<td class="select"><a href="#upload-lfs-image">generic</a></td>
<td class="select"><a href="#upload-lfs-image">generic</a></td>
</tr>
</table>
How to read this
Use case: you're just starting with NodeMCU and your OS of choice is Windows (and you are not using LFS), then the blue boxes in the 'Windows' column are your guideline. You:
- build the firmware on the cloud builder
- download and run the NodeMCU PyFlasher to transfer the firmware to the device
- download and run ESPlorer, which requires Java, to transfer Lua files from your system to the device
Missing tools?
Our intention is to introduce you to programming in Lua on the ESP8266 as quickly as possible, so we have kept the number of tools mentioned here to a minimum; frightanic.com: Tools and IDEs discusses other tools and options.
!!! caution
The below chapters are not meant to be followed one-by-one. Pick a task from the matrix above and it will take you to the relevant chapter.
Cloud Builder
The cloud builder at https://nodemcu-build.com allows to pick NodeMCU branch, modules and a few other configuration options (e.g. SSL yes/no). After the build is completed you will receive an email with two links to download your custom firmware:
- one for NodeMCU with floating support
- one for NodeMCU without floating support i.e. an integer-only binary
We recommend using the floating point build, even though the integer variant uses less RAM for storing variables, as there is little runtime difference between the two variants. Furthermore, the floating point variant handles non-integer values properly and this greatly simplifies numeric calculations.
For everything else the cloud builder GUI is self-explanatory. Hence, no need for further explanations here.
For LFS
1. Expand the "LFS options" panel
1. Select an LFS size, 64KB is likely going to be large enough
1. Select other options and build
_Note that this service is not maintained by the NodeMCU team. It's run by a NodeMCU team member as an individual, though._
NodeMCU PyFlasher
Self-contained NodeMCU flasher with GUI based on Python, esptool.py (see below) and wxPython. A runnable .exe is available for Windows and a .dmg for macOS.
No installation required on Windows and macOS! Instructions how to run it on other platforms are available on the project site.
1. Install drivers for USB-to-serial. Which driver you need depends on the ESP8266 module or USB-to-serial converter you use.
1. Connect USB cable to device and computer.
1. Download then start PyFlasher
1. Select serial port, browse for firmware binary and set the flash options.
_Note that this tool is not an official NodeMCU offering. It's maintained by a NodeMCU team member as an individual, though._
esptool.py
esptool.py was started as a ESP8266 community effort but has since been adopted by Espressif. It's their officially recommended way to flash firmware to ESPxxx chips.
1. Install drivers for USB-to-serial. Which driver you need depends on the ESP8266 module or USB-to-serial converter you use.
1. Install either Python 2.7 or Python >=3.4 on your system if it's not available yet.
1. Connect USB cable to device and computer.
1. $ pip install esptool (also installs pySerial)
1. $ esptool.py --port <serial-port-of-ESP8266> --baud <baud-rate> write_flash -fm <flash-mode> 0x00000 <nodemcu-firmware>.bin
flash-mode is qio for most ESP8266 ESP-01/07 (512 kByte modules) and dio for most ESP32 and ESP8266 ESP-12 (>=4 MByte modules). ESP8285 requires dout.
The default baud rate is 115200. Most hardware configurations should work with 230400 dependent on OS, driver, and module. NodeMCU and WeMos modules are usually ok with 921600.
More details available on esptool.py GitHub repo.
ESPlorer
TBD https://github.com/4refr0nt/ESPlorer
NodeMCU-Tool
Arguably NodeMCU-Tool, which requires Node.js, is the better code upload & execution tool than ESPlorer. Also, in contrast to the former it is very well maintained. However, we also understand that Windows users in general prefer GUI over command line.
The list of features is quite long but essentially NodeMCU-Tool offers:
- upload (Lua) files from your host system to the device
- manage the device file system (delete, up-/download, etc.)
- run files on NodeMCU and display the output over UART/serial
Quick start:
1. Install Node.js and NPM if not available yet
1. Install NodeMCU-Tool globally $ npm install nodemcu-tool -g
1. Verify installation by runnin $ nodemcu-tool --version
1. Upload a Lua file $ nodemcu-tool upload --port=/dev/ttyUSB0 helloworld.lua
1. Run it $ nodemcu-tool run helloworld.lua
Note that you may need to use the sudo prefix to install the tool at step 2, and also possibly add the āunsafe-perm flag after the install command.
Docker
The Docker NodeMCU build image is the easiest method to build NodeMCU related components locally on your preferred platform.
Offering:
- build NodeMCU firmware based on locally cloned sources and configuration
- cross-compile Lua files into LFS image locally
Detailed instructions available in the image's README. As for available config options check the documentation and study the comments in app/include/user_config.h.
For LFS
1. In app/include/user_config.h edit the line #define LUA_FLASH_STORE 0x0 and adjust the size to that needed. Note that this must be a multiple of 4Kb.
2. Build as you would otherwise build with this image (i.e. see its README)
_Note that this Docker image is not an official NodeMCU offering. It's maintained by a NodeMCU team member as an individual, though._
Build luac.cross
A local copy of luac.cross is only needed if you want to compile the Lua files into an LFS image yourself and you are _not_ using Docker.
Windows
Windows users can compile a local copy of the
luac.cross executable for use on a development PC. To this you need:- To download the current NodeMCU sources (this dev ZIP file or release ZIP file) and unpack into a local folder, say C:\nodemcu-firmware; choose the master / dev versions to match the firmware version that you want to use. If you want an Integer buld then edit the app/includes/user_config.h file to select this.
- Choose a preferred toolchain to build your luac.cross executable. You have a number of options here:
- If you are a Windows 10 user with the Windows Subsystem for Linux (WSL) already installed, then this is a Linux environment so you can follow the Linux build instructions below.
- A less resource intensive option which works on all Windows OS variants is to use Cygwin or MinGW, which are varaint ports of the GNU Compiler Collection to Windows and which can both compile to native Windows executables. In the case of Cygwin, install Cygwin (selecting the Cygwin core + gcc-core + gnu make in the install menu). In the case of MinGW you again only need a very basic C build environment so install the MINGW; you only need the core GCC and mingw32-make. Both both these create a Cmd prompt which paths in the relevant GCC toolchain. Switch to the app/lua/luac_cross and run make to build the compiler in the NodeMCU firmware root directory. You do this by rning make in Cygwin and mingw32-make -f mingw32-Makefile.mak in MinGW.
- You can also use MS Visual Studio (free community version is available). Just open the supplied MS solution file (msvc\hosttools.sln) and build it to get the Lua 5.1 luac.cross.exe file. Currently there is no sln file available for the Lua 5.3 version.
- Once you have a built luac.cross executable, then you can use this to compile Lua code into an LFS image. You might wish to move it out of the nodemcu-firmware hierarchy, since this folder hierarchy is no longer required and can be removed.
Linux
- Ensure that you have a "build essential" GCC toolchain installed.
- Download the current NodeMCU sources (this dev ZIP file or release ZIP file) and unpack into a local folder; choose the master / dev versions to match the firmware version that you want to use. If you want an Integer buld then edit the app/includes/user_config.h file to select this.
- Change directory to the app/lua/luac_cross sub-folder
- Run make to build the executable.
- Once you have a built luac.cross executable, then you can use this to compile Lua code into an LFS image. You might wish to move this out of the nodemcu-firmware hierarchy, since this folder hierarchy is no longer required and can be trashed.
macOS
As for Linux
Compile Lua into LFS image
Select Lua files to be run from LFS
The easiest approach is to maintain all the Lua files for your project in a single directory on your host. (These files will be compiled by luac.cross to build the LFS image in next step.)
For example to run the Telnet and FTP servers from LFS, put the following files in your project directory:
* lua_examples/lfs/_init.lua. LFS helper routines and functions.
* lua_examples/lfs/dummy_strings.lua. Moving common strings into LFS.
* lua_examples/telnet/telnet_fifosock.lua. A simple telnet server (example 1).
* lua_examples/telnet/telnet_pipe.lua. A simple telnet server (example 2).
* lua_modules/ftp/ftpserver.lua. A simple FTP server.
You should always include the first two modules, but the remaining files would normally be replaced by your own project files. Also remember that these are examples and that you are entirely free to modify or to replace them for your own application needs.
!!! Note
You will need to grab a luac.cross compiler that matches your configuration regarding float/integer, Lua 5.1/5.3 and possibly the release.
Terry's LFS Lua Cross-Compile Web Service
https://blog.ellisons.org.uk/article/nodemcu/a-lua-cross-compile-web-service/
Note: read up on selecting Lua files first
Upload a ZIP file with all your Lua files ready for LFS. The webservice will cross-compile them into a .img ready to be uploaded to the device. It supports LFS images for both floating point and integer firmware variants.
Further details available on the service site.
_Note that this service is not maintained by the NodeMCU team. It's run by a NodeMCU team member as an individual, though._
Docker
Note: read up on selecting Lua files first
The same Docker image you used to build the NodeMCU firmware can be used to compile Lua files into an LFS image.
1. $ cd <your-nodemcu-firmware-folder>
1. $ docker run --rm -ti -v pwd:/opt/nodemcu-firmware -v {PathToLuaSourceFolder}:/opt/lua marcelstoer/nodemcu-build lfs-image
Native on OS
Note: read up on selecting Lua files first
For Windows if you built with WSL / Cygwin you will do this from within the respective command window, both of which use the bash shell.
If you used Visual Studio just use the windows cmd window.
1. $ cd <project-dir>
1. $ luac.cross -o lfs.img -f *.lua
You will need to adjust the img and lua paths according to their location, and ensure that luac.cross is in your $PATH search list. For example if you are using WSL and your project files are in D:\myproject then the Lua path would be /mnt/d/myproject/*.lua (For cygwin replace mnt by cygwin). This will create the lfs.img file if there are no Lua compile errors (again specify an explicit directory path if needed).
You might also want to add a simple one-line script file to your ~/bin directory to wrap this command up.
Upload LFS image
The compiled LFS image file (e.g. lfs.img) is uploaded as a regular file to the device file system (SPIFFS). You do this just like with Lua files with e.g. ESPlorer or NodeMCU-Tool. There is also a new example, HTTP_OTA.lua, in lua_examples that can retrieve images from a standard web service.
Once the LFS image file is on SPIFFS, you can execute the node.flashreload() command and the loader will then load it into flash and immediately restart the ESP module with the new LFS loaded, if the image file is valid. However, the call will return with an error _if_ the file is found to be invalid, so your reflash code should include logic to handle such an error return.
Edit your init.lua file
init.lua is the file that is first executed by the NodeMCU firmware. Usually it setups the WiFi connection and executes the main Lua application. Assuming that you have included the _init file discussed above, then executing this will add a simple API for LFS module access:
- Individual functions can be executed directly, e.g. LFS.myfunc(a,b)
- LFS is now in the require path, so require 'myModule' works as expected.
Do a protected call of this _init code: pcall(node.LFS._init()) and check the error status. See Programming Techniques and Approachs in the LFS whitepaper for a more detailed description.
Minimal LFS example
Below is a brief overview of building and running the simplest LFS-based system possible.
To use LFS, start with a version of the NodeMCU firmware with LFS enabled. See the matrix section "Build LFS
enabled firmware" for how to do that. Load it on the ESP8266 in the usual way (whatever that is for your set up).
Then build an LFS file system. This can be done in several ways, as discussed above; one of the easiest is to use luac.cross -o lfs.img -f *lua on the host machine. Make sure to include a file named hello_world.lua with the following one line content: print("Hello ESP8266 world!")
The file lua_examples/lfs/_init.lua should definitely be included in the image, since it's the easiest way to integrate the LFS system. The lfs.img file can then be downloaded to the ESP8266 just like any other file.
The next step is to tell the ESP8266 that the LFS exists. This is done with node.LFS.reload("lfs.img"), which will trigger a reset, followed by node.LFS._init() to better integrate LFS; logging into the esp8266 and running the following commands gives an overview of the command sequence.
> node.LFS.reload("lfs.img")
-- node.LFS.reload() triggers one or two resets here.
-- Call the LFS hello_world.
node.LFS.hello_world()
Hello ESP8266 world!
-- DONE!-- now for some more insights and helpers
-- List the modules in the LFS.
print(node.LFS.list)
function: 3fff0728
for k,v in pairs(node.LFS.list()) do print(k,v) end
1 dummy_strings
2 _init
3 hello_world
-- integrate LFS with SPIFFS
node.LFS._init()
-- We now can run and load files from SPIFFS or LFS using dofile and loadfile.
dofile("hello_world.lua")
Hello ESP8266 world!
-- require() also works the same way now.
-- if there was a file called "hello_world.lua" in SPIFFS the that would be executed. But if there isn't a lookup in LFS is made.
-- _init.lua also sets a global LFS as a copy of node.LFS. This is somewhat backwards compatibility and might get removed in the future.
print(LFS)
table: 3fff06e0
Note that no error correction has been used, since the commands are intended to be entered at a terminal, and errors will become obvious.
Then you should set up the ESP8266 boot process to check for the existence of an LFS image and run whichever module is required. Once the LFS module table has been registered by running lua_examples/lfs/_init.lua, running an LFS module is simply a matter of eg: LFS.hello_world().
node.LFS.reload() need only be rerun if the LFS image is updated; after it has loaded the LFS image into flash memory the original file (in SPIFFS) is no longer used, and can be deleted.
Once LFS is known to work, then modules such as lua_examples/lfs/dummy_strings.lua can usefully be added, together of course with effective error checking.
---
Img/Favicon Readme
favicon.ico was generated using https://realfavicongenerator.net. favicon_package_v0.16.zip in this folder contains icons and instructions for all sorts of browsers and platforms (incl. mobile variants). However, without modifying the MkDocs theme/template theyāre of no use.
---
Lua Modules/Bh1750
BH1750 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-01-30 | Martin Han | Martin Han | bh1750.lua |
This Lua module provides access to BH1750 I²C ambient light sensor.
!!! note
This module requires i2c C module built into firmware.
Require
bh1750 = require("bh1750")Release
bh1750 = nil
package.loaded["bh1750"] = nilbh1750.init()
Initializes the module and sets up I²C with hardcoded device address.
#### Syntaxbh1750.init(sda, scl)
#### Parameters
- sda SDA pin number.
- scl SCL pin number.
#### Returnsnil
bh1750.read()
Reads lux value from the sensor.
#### Syntaxbh1750.read()
#### Parameters
None
#### Returns
Lux value.
bh1750.getlux()
Function used to return last read lux value.
#### Syntaxbh1750.getlux()
#### Parameters
None
#### Returns
Last known lux value.
#### Example
SDA_PIN = 6 -- sda pin, GPIO12
SCL_PIN = 5 -- scl pin, GPIO14bh1750 = require("bh1750")
bh1750.init(SDA_PIN, SCL_PIN)
bh1750.read()
l = bh1750.getlux()
print("lux: "..(l / 100).."."..(l % 100).." lx")
-- release module
bh1750 = nil
package.loaded["bh1750"] = nil
---
Lua Modules/Bme280
BME280 module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2020-10-04 | vsky279 | vsky279 | bme280.lua|
This module communicates with BME280/BMP280 temperature/air presssure/humidity sensors (Bosch Sensortec) through I2C interface.
!!! note
The module works only with the bme280_math module.
!!! caution
The BMP280 only supports temperature and air pressure measurements. It will give wrong readings for humidity but no warnings or errors. Sometimes sellers of breakout boards for these sensors confuse the two and sell one as the other.
To easily check if you have a BMP280 or a BME280 look at the shape of the sensor: The BMP280 has rectangular shape, whereas the BME280 has a square one.
bme280.setup()
Creates bme280sensor object and initializes the module. Initialization is mandatory before reading values. Note that there has to be a delay between some tens to hundreds of milliseconds between calling setup() and reading measurements.
Functions supported by bme280sensor object:
- setup()
- read()
- startreadout()
- qfe2qnh
- altitude
- dewpoint
#### Syntax
bme280.setup(id, [address, temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter])
#### Parameters
- id - I2C bus number
- (optional)address - BME280 sensor address. 1 for BME280_I2C_ADDRESS1 = 0x76, 2 for BME280_I2C_ADDRESS2 = 0x77. Default sensor address is BME280_I2C_ADDRESS1.
- (optional) temp_oss - Controls oversampling of temperature data. Default oversampling is 16x.
- (optional) press_oss - Controls oversampling of pressure data. Default oversampling is 16x.
- (optional) humi_oss - Controls oversampling of humidity data. Default oversampling is 16x
- (optional) sensor_mode - Controls the sensor mode of the device. Default sensor more is normal.
- (optional) inactive_duration - Controls inactive duration in normal mode. Default inactive duration is 20ms.
- (optional) IIR_filter - Controls the time constant of the IIR filter. Default filter coefficient is 16.
- (optional) cold_start - If 0 then the BME280 chip is not initialised. Useful in a battery operated setup when the ESP deep sleeps and on wakeup needs to initialise the driver (the module) but not the chip itself. The chip was kept powered (sleeping too) and is holding the latest reading that should be fetched quickly before another reading starts (bme280sensor:startreadout()). By default the chip is initialised.
|temp_oss, press_oss, humi_oss|Data oversampling|
|-----|-----------------|
|0|Skipped (output set to 0x80000)|
|1|oversampling Ć1|
|2|oversampling Ć2|
|3|oversampling Ć4|
|4|oversampling Ć8|
|5|oversampling Ć16|
|sensor_mode|Sensor mode|
|-----|-----------------|
|0|Sleep mode|
|1 and 2|Forced mode|
|3|Normal mode|
Using forced mode is recommended for applications which require low sampling rate or hostbased synchronization. The sensor enters into sleep mode after a forced readout. Please refer to BME280 Final Datasheet for more details.
|inactive_duration|t standby (ms)|
|-----|-----------------|
|0|0.5|
|1|62.5|
|2|125|
|3|250|
|4|500|
|5|1000|
|6|10|
|7|20|
|IIR_filter|Filter coefficient |
|-----|-----------------|
|0|Filter off|
|1|2|
|2|4|
|3|8|
|4|16|
#### Returnssobj - BME280 Sensor Object (nil if initialization has failed)
BME280 Sensor Object Methods
sobj:setup()
Re-initializes the sensor.
Parameters
Parameters are the same as for the bme280.setup function.
Return
Returned values are the same as for the bme280.setup function.
sobj:altitude()
For given air pressure (called QFE in aviation - see wiki QNH article) and sea level air pressure returns the altitude in meters, i.e. altimeter function.
#### Syntaxsobj:altitude(P, QNH)
#### Parameters
- P measured pressure
- QNH current sea level pressure
#### Returns
altitude in meters of measurement point
sobj:dewpoint()
For given temperature and relative humidity returns the dew point in celsius.
#### Syntaxsobj:dewpoint(H, T)
#### Parameters
- H relative humidity in percent (100 means 100%)
- T temperate in celsius
#### Returns
dew point in celsisus
sobj:qfe2qnh()
For given altitude converts the air pressure to sea level air pressure (QNH).
#### Syntaxsobj:qfe2qnh(P, altitude)
#### Parameters
- P measured pressure
- altitude altitude in meters of measurement point
#### Returns
sea level pressure
sobj:read()
Reads the sensor and returns the temperature, the air pressure, the air relative humidity and see level pressure when altitude is specified.
#### Syntaxsobj:read([altitude])
#### Parameters
- (optional) altitude- altitude in meters of measurement point. If provided also the air pressure converted to sea level air pressure is returned.
#### Returns
- T temperature in celsius
- P air pressure in hectopascals
- H relative humidity in percent
- (optional) QNH air pressure in hectopascals (when altitude is specified)
Returns nil if the readout is not successful.
sobj:startreadout()
Starts readout (turns the sensor into forced mode). After the readout the sensor turns to sleep mode. Callback function is called with readout results.
#### Syntaxsobj:startreadout(delay, callback)
#### Parameters
- callback if provided it will be invoked after given delay. Callback parameters are identical to sobj:read results.
- altitude in meters of measurement point (QNH is returned when specified)
- delay sets sensor to forced mode and calls the callback (if provided) after given number of milliseconds. For 0 the default delay is set to 113ms (sufficient time to perform reading for oversampling settings 16x). For different oversampling setting please refer to BME280 Final Datasheet - Appendix B: Measurement time and current calculation.
#### Returnsnil
#### Example
alt=320 -- altitude of the measurement placesda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW)
s = require('bme280').setup(0)
tmr.create():alarm(500, tmr.ALARM_AUTO, function()
local T, P, H, QNH = s:read(alt)
local D = s:dewpoint(H, T)
print(("T=%.2f, QFE=%.3f, QNH=%.3f, humidity=%.3f, dewpoint=%.2f"):format(T, P, QNH, H, D))
end)
Example with sensor in sleep mode between readouts (asynchronous readouts)
alt=320 -- altitude of the measurement placesda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW)
s = require('bme280').setup(0, nil, nil, nil, nil, 0) -- initialize to sleep mode
tmr.create():alarm(1000, tmr.ALARM_AUTO, function()
s:startreadout(function(T, P, H, QNH)
local D = s:dewpoint(H, T)
print(("T=%.2f, QFE=%.3f, QNH=%.3f, humidity=%.3f, dewpoint=%.2f"):format(T, P, QNH, H, D))
end, alt)
end)
Altimeter function - calculate altitude based on current sea level pressure (QNH) and measure pressure
alt = 0 -- initial altitudesda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW)
s = require('bme280').setup(0)
tmr.create():alarm(100, tmr.ALARM_AUTO, function()
local _, P, _, lQNH = s:read(alt)
if not QNH then QNH = lQNH end
local altitude = s:altitude(P, QNH)
print(("altitude=%.3f m"):format(altitude))
end)
---
Lua Modules/Cohelper
cohelper Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2019-07-24 | TerryE | TerryE | cohelper.lua |
This module provides a simple wrapper around long running functions to allow
these to execute within the SDK and its advised limit of 15 mSec per individual
task execution. It does this by exploiting the standard Lua coroutine
functionality as described in the Lua RM §2.11 and PiL Chapter 9.
The NodeMCU Lua VM fully supports the standard coroutine functionality. Any
interactive or callback tasks are executed in the default thread, and the coroutine
itself runs in a second separate Lua stack. The coroutine can call any library
functions, but any subsequent callbacks will, of course, execute in the default
stack.
Interaction between the coroutine and the parent is through yield and resume
statements, and since the order of SDK tasks is indeterminate, the application
must take care to handle any ordering issues. This particular example uses
the node.task.post() API with the taskYield()function to resume itself,
so the running code can call taskYield() at regular points in the processing
to spilt the work into separate SDK tasks.
A similar approach could be based on timer or on a socket or pipe CB. If you
want to develop such a variant then start by reviewing the source and understanding
what it does.
Require
local cohelper = require("cohelper")
-- or linked directly with the exec() method
require("cohelper").exec(func, <params>)Release
Not required. All resources are released on completion of the exec() method.
cohelper.exec()
Execute a function which is wrapped by a coroutine handler.
#### Syntaxrequire("cohelper").exec(func, <params>)
#### Parameters
- func: Lua function to be executed as a coroutine.
- <params>: list of 0 or more parameters used to initialise func. the number and types must be matched to the funct declaration
#### Returns
Return result of first yield.
#### Notes
1. The coroutine function func() has 1+_n_ arguments The first is the supplied task yield function. Calling this yield function within func() will temporarily break execution and cause an SDK reschedule which migh allow other executinng tasks to be executed before is resumed. The remaining arguments are passed to the func() on first call.
2. The current implementation passes a single integer parameter across resume() / yield() interface. This acts to count the number of yields that occur. Depending on your appplication requirements, you might wish to amend this.
Full Example
Here is a function which recursively walks the globals environment, the ROM table
and the Registry. Without coroutining, this walk terminate with a PANIC following
a watchdog timout. I don't want to sprinkle the code with tmr.wdclr() that could
in turn cause the network stack to fail. Here is how to do it using coroutining:
require "cohelper".exec(
function(taskYield, list)
local s, n, nCBs = {}, 0, 0 local function list_entry (name, v) -- upval: taskYield, nCBs
print(name, v)
n = n + 1
if n % 20 == 0 then nCBs = taskYield(nCBs) end
if type(v):sub(-5) ~= 'table' or s[v] or name == 'Reg.stdout' then return end
s[v]=true
for k,tv in pairs(v) do
list_entry(name..'.'..k, tv)
end
s[v] = nil
end
for k,v in pairs(list) do
list_entry(k, v)
end
print ('Total lines, print batches = ', n, nCBs)
end,
{_G = _G, Reg = debug.getregistry(), ROM = ROM}
)
---
Lua Modules/Ds18b20
DS18B20 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2014-12-08 | Huang Rui | Huang Rui | ds18b20.lua |
This Lua module provides access to DS18B20 1-Wire digital thermometer.
For integer version of firmware use ds18b20-integer.lua module - measured temperatures are multiplied by 10000.
The module requires ow C module built into firmware.
Require
ds18b20 = require("ds18b20")Release
ds18b20 = nil
package.loaded["ds18b20"] = nilenable_debug()
Enables debug output of the module.
#### Parameters
None
#### Returnsnil
ds18b20.read_temp()
Scans the bus for DS18B20 sensors (optional), starts a readout (conversion) for all sensors and calls a callback function when all temperatures are available. Powered sensors are read at once first. Parasite-powered sensors are read one by one. The first parasite-powered sensor is read together with all powered sensors.
#### Syntaxread_temp(callback, pin, unit, force_search, save_search)
#### Parameters
- callback function that receives all results when all conversions finish. The callback function has one parameter - an array addressed by sensor addresses and a value of the temperature (string for integer version).
- pin pin of the one-wire bus. If nil, GPIO0 (3) is used.
- unit unit can be Celsius ("C" or ds18b20.C), Kelvin ("K" or ds18b20.K) or Fahrenheit ("F" or ds18b20.F). If not specified (nil) latest used unit is used.
- force_search if not nil a bus search for devices is performed before readout. If nil the existing list of sensors in memory is used. If the bus has not been searched yet the search performed as well.
- save_search if not nil found sensors are saved to the file ds18b20_save.lc. When read_temp is called, list of sensors in memory is empty and file ds18b20_save.lc is present then sensor addresses are loaded from file - useful when running from batteries & deepsleep - immediate readout is performed (no bus scan).
#### Returnsnil
#### Example
local t = require("ds18b20")
local pin = 3 -- gpio0 = 3, gpio2 = 4local function readout(temp)
if t.sens then
print("Total number of DS18B20 sensors: ".. #t.sens)
for i, s in ipairs(t.sens) do
print(string.format(" sensor #%d address: %s%s", i, ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(s:byte(1,8)), s:byte(9) == 1 and " (parasite)" or ""))
end
end
for addr, temp in pairs(temp) do
print(string.format("Sensor %s: %s °C", ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(addr:byte(1,8)), temp))
end
-- Module can be released when it is no longer needed
t = nil
package.loaded["ds18b20"] = nil
end
t:read_temp(readout, pin, t.C)
ds18b20.sens
A table with sensors present on the bus. It includes its address (8 bytes) and information whether the sensor is parasite-powered (9-th byte, 0 or 1).
ds18b20.temp
A table with readout values (also passed as a parameter to callback function). It is addressed by sensor addresses.
#### Notes
Other examples of using this module can be found in ds18b20-example.lua and ds18b20-web.lua files.
---
Lua Modules/Ds3231
DS3231 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-01-19 | Tobie Booth | Tobie Booth | ds3231.lua |
This Lua module provides access to DS3231 I²C real-time clock.
!!! note
This module requires i2c C module built into firmware.
Require
ds3231 = require("ds3231")Release
ds3231 = nil
package.loaded["ds3231"] = nilds3231.setTime()
Sets the current date and time. If _disableOscillator_ is set to 1 the oscillator will stop on battery.
#### Syntaxds3231.setTime(second, minute, hour, day, date, month, year[, disableOscillator])
#### Parameters
- second: 00-59
- minute: 00-59
- hour: 00-23
- day: 1-7 (Sunday = 1, Saturday = 7)
- date: 01-31
- month: 01-12
- year: 00-99
- disableOscillator: (optional) 0-1, defaults to 0 if omitted
#### Returnsnil
#### Example
i2c.setup(3, 4, scl, i2c.SLOW) -- call i2c.setup() only onceds3231 = require("ds3231")
-- Set date and time to Sunday, January 18th 2015 6:30PM
ds3231.setTime(0, 30, 18, 1, 18, 1, 15);
-- Don't forget to release it after use
ds3231 = nil
package.loaded["ds3231"] = nil
ds3231.getTime()
Get the current date and time.
#### Syntaxds3231.getTime()
#### Parameters
None
#### Returns
- second: integer. Second 00-59
- minute: integer. Minute 00-59
- hour: integer. Hour 00-23
- day: integer. Day 1-7 (Sunday = 1, Saturday = 7)
- date: integer. Date 01-31
- month: integer. Month 01-12
- year: integer. Year 00-99
#### Example
i2c.setup(3, 4, scl, i2c.SLOW) -- call i2c.setup() only onceds3231=require("ds3231")
-- Get date and time
second, minute, hour, day, date, month, year = ds3231.getTime();
-- Print date and time
print(string.format("Time & Date: %s:%s:%s %s/%s/%s",
hour, minute, second, date, month, year))
-- Don't forget to release it after use
ds3231 = nil
package.loaded["ds3231"] = nil
ds3231setAlarm()
Set an alarm to be triggered on SQW pin. _alarm1_ has a precision of seconds; _alarm2_ has a precision of minutes (
second parameter will be ignored). Alarms sets gpio.LOW over the SQW pin and let it unchanged until reloaded. When reloaded sets gpio.HIGH. Alarms trigger only once, after that, if you want them to trigger again, you need to call reloadAlarms() or setAlarm(...) again.Alarm type set the alarm match conditions:
- ds3231.EVERYSECOND works only with _alarm1_ and triggers every second;
- ds3231.EVERYMINUTE works only with _alarm2_ and triggers every minute (at 00 seconds);
- ds3231.SECOND triggers when time match given seconds parameter;
- ds3231.MINUTE triggers when time match given seconds and minutes parameters;
- ds3231.HOUR triggers when time match given seconds, minutes, and hours parameters;
- ds3231.DAY triggers when time match given seconds, minutes, and hours on week day date/day parameters;
- ds3231.DATE triggers when time match given seconds, minutes, and hours on date (day of the month) date/day parameters;
#### Syntaxds3231.setAlarm(alarmId, alarmType, seconds, minutes, hours, date/day)
#### Parameters
- alarmId: 1-2
- alarmType: 1-7
- seconds: 00-59
- minutes: 00-59
- hours: 00-23
- date/day: 01-31 or 1-7 (Sunday = 1, Saturday = 7)
#### Returnsnil
#### Example
i2c.setup(3, 4, scl, i2c.SLOW) -- call i2c.setup() only onceds3231=require("ds3231")
-- Setting PIN1 to triggers on interrupt when alarm triggers
gpio.mode(1,gpio.INT)
gpio.trig(1,'down',function(level)
print('Time is passing')
-- If not reloaded it will be triggered only once
ds3231.reloadAlarms()
end)
ds3231.setAlarm(2,ds3231.EVERYMINUTE)
-- Don't forget to release it after use
ds3231 = nil
package.loaded["ds3231"] = nil
ds3231.reloadAlarms()
Reload an already triggered alarm. Otherwise it will never be triggered again. There are two different alarms and they have to be reloaded both to let, even only one, to be triggered again. So there isn't a param to select which alarm to reload.
#### Syntaxds3231.reloadAlarms()
#### Parameters
None
#### Returnsnil
#### Example
i2c.setup(3, 4, scl, i2c.SLOW) -- call i2c.setup() only onceds3231=require("ds3231")
-- Setting PIN1 to triggers on interrupt when alarm triggers
gpio.mode(1,gpio.INT)
gpio.trig(1,'down',function(level)
print('Time is passing')
-- If not reloaded it will be triggered only once
ds3231.reloadAlarms()
end)
ds3231.setAlarm(2,ds3231.EVERYMINUTE)
-- Don't forget to release it after use
ds3231 = nil
package.loaded["ds3231"] = nil
ds3231.enableAlarm()
Enable an already setted alarm with the previous matching conditions. It reloads alarms internally.
#### Syntaxds3231.enableAlarm(alarmId)
#### ParametersalarmId: 1-2
#### Returnsnil
#### Example
i2c.setup(3, 4, scl, i2c.SLOW) -- call i2c.setup() only onceds3231=require("ds3231")
-- Trigger on x:20:15
ds3231.setAlarm(1,ds3231.MINUTE,15,20)
if badThing == 1 then
ds3231.disableAlarm(1)
end
if goodThing == 1 then
ds3231.enableAlarm(1)
end
-- Don't forget to release it after use
ds3231 = nil
package.loaded["ds3231"] = nil
ds3231.disableAlarm()
Disable an already set alarm with the previous matching conditions.
if _alarmId_ is not 1 or 2 it disables both alarms.
Warning: disableAlarm() prevent alarms to trigger interrupt over SQW pin but alarm itself will triggers at the matching conditions as it could be seen on _status byte_.
#### Syntaxds3231.disableAlarm(alarmId)
#### ParametersalarmId: 0-2
#### Returnsnil
#### Example
i2c.setup(3, 4, scl, i2c.SLOW) -- call i2c.setup() only onceds3231=require("ds3231")
-- Trigger on x:20:15
ds3231.setAlarm(1,ds3231.MINUTE,15,20)
if badThing == 1 then
ds3231.disableAlarm(1)
end
if goodThing == 1 then
ds3231.enableAlarm(1)
end
-- Don't forget to release it after use
ds3231 = nil
package.loaded["ds3231"] = nil
ds3231.getBytes()
Get bytes of control, for debug purpose, and status of DS3231. To see what they means check the datasheet.
#### Syntaxds3231.getBytes()
#### Parameters
None
#### Returns
- control: integer. Control 0-255
- status: integer. Status 0-143 (bit 6-5-4 unused)
#### Example
i2c.setup(3, 4, scl, i2c.SLOW) -- call i2c.setup() only onceds3231=require("ds3231")
control,status = ds3231.getBytes()
print('Control byte: '..control)
print('Status byte: '..status)
-- Don't forget to release it after use
ds3231 = nil
package.loaded["ds3231"] = nil
da3231.resetStopFlag()
Stop flag on status byte means that the oscillator either is stopped or was stopped for some period and may be used to judge the validity of the timekeeping data. When set to 1 this flag keeps that values until changed to 0. Call
resetStopFlag() if you need to check validity of time data after that.#### Syntaxds3231.resetStopFlag()
#### Parameters
None
#### Returnsnil
#### Example
i2c.setup(3, 4, scl, i2c.SLOW) -- call i2c.setup() only onceds3231=require("ds3231")
control,status = ds3231.getBytes()
if bit.band(bit.rshift(status, 7),1) == 1 then
print('[WARNING] RTC has stopped')
ds3231.resetStopFlag()
end
-- Don't forget to release it after use
ds3231 = nil
package.loaded["ds3231"] = nil
#### Notes
Other examples of using this module can be found in ds3231-example.lua and ds3231-web.lua files.
---
Lua Modules/Fifo
FIFO Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2019-02-10 | nwf | nwf | fifo.lua |
This module provides flexible, generic FIFOs built around Lua tables and
callback functions. It is specifically engineered to work well with the
NodeMCU event-based and memory-constrained environment.
Constructor
fifo = (require "fifo").new()fifo.dequeue()
#### Syntax
fifo:dequeue(k)Fetch an element from the fifo and pass it to the function k, together with a
boolean indicating whether this is the last element in the fifo. If the fifo
is empty, k will not be called and the fifo will enter "immediate dequeue"
mode (see below).
Assuming k is called, ordinarily, k will return nil, which will cause the
element given to k to be removed from the fifo and the queue to advance. If,
however, k returns a non-nil value, that value will replace the element at
the head of the fifo. This may be useful for generators, for example, which
stand in for several elements.
When k returns nil, it may also return a boolean as its second result. If
that is false, processing ends and fifo:dequeue returns. If that istrue, the fifo will be advanced again (i.e. fifo:dequeue(k) will be *tail
called*). Elements for which k returns nil, true are called "phantom", as
they cause the fifo to act as though they were not there. Phantom elements are
useful for callback-like behavior as the fifo advances: when k sees a phantom
element, it knows that all prior entries in the fifo have been seen, but the
phantom does not necessarily know how to generate the next element of the fifo.
#### Returnstrue if the queue contained at least one non-phantom entry, false otherwise.
fifo.queue()
#### Syntax
fifo:queue(a,k)Enqueue the element a onto the fifo. If k is not nil and the fifo is in
"immediate dequeue" mode (whence it starts), immediately pass the first element
of the fifo (usually, but not necessarily, a) to k, as if fifo:dequeue(k)
had been called, and exit "immediate dequeue" mode.
FIFO Elements
The elements stored in the FIFO are simply the integer indices of the fifo
table itself, with 1 being the head of the fifo. The depth of the queue for
a given fifo is just its table size, i.e. #fifo. Direct access to the
elements is strongly discouraged. The number of elements in the fifo is also
unlikely to be of interest; especially, decisions about the fifo's emptiness
should instead be rewritten to use the existing interface, if possible, or may
peek a bit at the immediate dequeueing state (see below). See the discussion
of corking, below, too.
Immediate Dequeueing
The "immediate dequeue" behavior may seem counterintuitive, but it is very
useful for the case that fifo:dequeue's k arranges for subsequent
invocations of fifo:dequeue, say by scheduling the next invocation of a timer
or by sending on a socket with an on("sent") callback wired tofifo:dequeue.
Because the fifo enters "immediate dequeue" mode only when dequeue has been
called and the fifo was empty at the time of the call, rather than when the
fifo becomes empty, fifo:queue will sometimes not invoke its k even if
the queued element a ends up at the front of the fifo. This, too, is quite
useful: it ensures that k will not be called in contexts where it would
overlap any ongoing processing of the most-recently dequeued, fifo-emptying
element.
The immediate deququeing status of the fifo is visible as the _go member,
which may be read (even if said reads are politely discouraged, but on occasion
it is handy to know) but should never be written.
Corking
The fifo has no special support for corking (that is, queueing several elements
which are guaranteed to not be dequeued until some later point, called
"uncorking"). As one often wants to cork only when the fifo is transitioning
out of immediate deququeing mode, the existing machinery is generally good
enough to provide an easy emulation thereof. While it is typical to pass the
same k to both :queue and :dequeue, there is nothing necessitating this
convention. And so one may, as in the fifosock module, use the :queuek to record the transition out of immediate dequeueing mode for later,
when one wishes to uncork:
local corked = false
fifo:queue(e1, function(e) corked = true ; return e end)
-- e1 is now in the fifo, and corked is true if the fifo has exited
-- immediate dequeue mode. e1 will be returned back to the fifo and
-- so will not be deququed by the function argument. -- We can now queue more elements to the fifo. These will certainly
-- queue behind e1.
fifo:queue(e2)
-- If we should have initiated draining the fifo above, we can do so now,
-- instead, having built up a backlog as desired.
if corked then fifo:dequeue(k) end
---
Lua Modules/Fifosock
fifosock Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2019-02-10 | TerryE | nwf | fifosock.lua |
This module provides a moderately convenient, efficient wrapper around thenet.socket send method. It ensures in-order transmission while striving to
minimize memory footprint and packet count by coalescing queued strings. It
also serves as a detailed, worked example of the fifo module.
Use
ssend = (require "fifosock").wrap(sock)
ssend("hello, ") ssend("world\n")-- when finished
ssend = nil
sock:on("sent", nil)
Once the socket has been wrapped, one should use only the resulting ssend
function in lieu of sock:send, and one should not change thesock:on("sent") callback for the duration of the connection.
Use of this module creates a circular reference through the Lua registry: the
socket points at the fifosock wrapper, which points back at the socket. As
such, it is vitally important to break this cycle when the socket has outlived
its use. The usual garbage collection will not be able to reclaim abandoned
wrapped sockets. The user of fifosock must, when disposing of the socket,
unwire the wrapper, by calling sock:on("sent", nil) and should drop all
references to ssend; a convenient place to do this is in thesock:on("disconnect") callback.
Advanced Use
In addition to passing strings representing part of the stream to be sent, it
is possible to pass the resulting ssend function functions. These
functions will be given no parameters, but should return two values:
- A string to be sent on the socket, or nil if no output is desired
- A replacement function, or nil if the function is to be dequeued. Functions
may, of course, offer themselves as their own replacement to stay at the front
of the queue.
This facility is useful for providing a replacement for the sock:on("sent")
callback channel. In the fragment below, "All sent" will be printed only
when the entirety of "hello, world\n" has been successfully sent on thesocket.
ssend("hello, ") ssend("world\n")
ssend(function() print("All sent") end) -- implicitly returns nil, nilThis facility is also useful for generators of the stream, roughly akin tosendfile-like primitives in larger systems. Here, for example, we can stream
SPIFFS data across the network without ever holding a large amount in RAM.
local function sendfile(fn)
local offset = 0
local function send()
local f = file.open(fn, "r")
if f and f:seek("set", offset) then
r = f:read()
f:close()
if r then
offset = offset + #r
return r, send
end
end
-- implicitly returns nil, nil and falls out of the stream
end
return send, function() return offset end
endlocal fn = "test"
ssend(("Sending file '%s'...\n"):format(fn))
dosf, getsent = sendfile(fn)
ssend(dosf)
ssend(("Sent %d bytes from '%s'\n"):format(getsent(), fn))
---
Lua Modules/Ftpserver
FTPServer Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2018-07-02 | Terry Ellison | Terry Ellison | ftpserver.lua |
This Lua module implementation provides a basic FTP server for the ESP8266. It has been tested against a number of Table, Windows and Linux FTP clients and browsers.
It provides a limited subset of FTP commands that enable such clients to transfer files to and from the ESP's file system. Only one server can be started at any one time, but this server can support multiple connected sessions (some FTP clients use multiple sessions and so require this feature).
!!! warning
This module is too big to load by standard require function or compile on ESP8266 using node.compile(). The only option to load and use it is to use LFS.
Limitations
- FTP over SSH or TLS is not currently supported so transfer is unencrypted.
- The client session , must, authenticate against a single user/password.
- Only the SPIFFS filesystem is currently supported, so changing directories is treated as a NO-OP.
- This implementation has been optimized for running in LFS.
- Only PASV mode is supported as the
net module does not allow static allocation of outbound sockets.Notes
The coding style adopted here is more similar to best practice for normal (PC) module implementations, as using LFS permits a bias towards clarity of coding over brevity. It includes extra logic to handle some of the edge case issues more robustly. It also uses a standard forward reference coding pattern to allow the code to be laid out in main routine, subroutine order.
Most FTP clients are capable of higher transfer rates than the ESP SPIFFS write throughput, so the server uses TCP flow control to limit upload rates to the ESP.
The following FTP commands are supported:
- with no parameter: CDUP, NOOP, PASV, PWD, QUIT, SYST
- with one parameter: CWD, DELE, MODE, PASS, PORT, RNFR, RNTO, SIZE, TYPE, USER
- xfer commands: LIST, NLST, RETR, STOR
This implementation is by Terry Ellison, but I wish to acknowledge the inspiration and hard work by Neronix that made this possible.
createServer()
Create the FTP server on the standard ports 20 and 21. The global variable
FTP is set to the server object.#### SyntaxFTP:createServer(user, pass[, dbgFlag])
#### Parameters
- user: Username for access to the server
- pass: Password for access to the server
- dbgFlag: optional flag. If set true then internal debug output is printed
#### Returnsnil
#### Example
require("ftpserver"):createServer('user', 'password')open()
Wrapper to createServer() which also connects to the WiFi channel.
#### SyntaxFTP:open(user, pass, ssid, wifipwd, dbgFlag)
#### Parameters
- user: Username for access to the server
- pass: Password for access to the server
- ssid: SSID for WiFi service
- wifipwd: password for WiFi service
- dbgFlag: optional flag. If set true then internal debug output is printed
#### Returnsnil
#### Example
require("ftpserver"):open('user', 'password', 'myWifi', 'wifiPassword')close()
Close down server including any sockets and return all resources to Lua. Note that this include removing the FTP global variable and package references.
#### SyntaxFTP:close()
#### Parameters
None
#### Returnsnil
#### Example
FTP:close()---
Lua Modules/Gossip
ESPGossip
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2020-01-20 | alexandruantochi | alexandruantochi | gossip.lua |
This module is based on the gossip protocol and it can be used to disseminate information through the network to other nodes. The time it takes for the information to reach all nodes is logN. For every round number n, 2^n nodes will receive the information.
Require
gossip = require('gossip')Release
gossip.inboundSocket:close()
gossip = nilUsage
config = {
seedList = { '192.168.0.1', '192.168.0.15' },
debug = true,
debugOutput = print
}
gossip = require ("gossip")
gossip.setConfig(config)
gossip.start()Strategy
Each controller will randomly pick an IP from it's seed list. It will send a SYN request to that IP and set receiving node's state to an intermediary state between Up and Suspect. The node that receives the SYN request will compute a diff on the received networkState vs own networkState. It will then send that diff as an ACK request. If there is no data to send, it will only send an ACK. When the ACK is received, the sender's state will revert to Up and the receiving node will update it's own networkState using the diff (based on the ACK reply).
Gossip will establish if the information received from another node has fresher data by first comparing the revision, then the heartbeat and lastly the state. States that are closer to DOWN have priority as an offline node does not update it's heartbeat.
Any other parameter can be sent along with the mandatory revision, heartbeat and state thus allowing the user to spread information around the network. Every time a node receives 'fresh' data, the gossip.updateCallback will be called with that data as the first parameter.
Currently there is no implemented deletion for nodes that are down except for the fact that their status is signaled as REMOVE.
Example use-case
There are multiple modules on the network that measure temperature. We want to know the maximum and minimum temperature at a given time and have every node display it.
The brute force solution would be to query each node from a single point and save the min and max values, then go back to each node and present them with the computed min and max. This requires n*2 rounds, where n is the number of nodes. It also opens the algorithm to a single point of failure (the node that is in charge of gathering the data).
Using gossip, one can have the node send it's latest value through SYN or pushGossip() and use the callbackUpdate function to compare the values from other nodes to it's own. Based on that, the node will display the values it knows about by gossiping with others. The data will be transmitted in ~log(n) rounds, where n is the number of nodes.
Terms
revision : generation of the node; if a node restarts, the revision will be increased by one. The revision data is stored as a file to provide persistency
heartBeat : the node uptime in seconds (tmr.time()). This is used to help the other nodes figure out if the information about that particular node is newer.
networkState : the list with the state of the network composed of the ip as a key and revision, heartBeat and state as values packed in a table.
state : all nodes start with a state set to UP and when a node sends a SYN request, it will mark the destination node in an intermediary state until it receives an ACK or a SYN from it. If a node receives any message, it will mark that senders IP as UP as this provides proof that the node is online.
setConfig()
#### Syntax
gossip.setConfig(config)Sets the configuration for gossip. The available options are:
seedList : the list of seeds gossip will start with; this will be updated as new nodes are discovered. Note that it's enough for all nodes to start with the same IP in the seedList, as once they have one seed in common, the data will propagate. If the seedList is empty a broadcast is sent, so this can be used for automatic discovery of nodes.
roundInterval: interval in milliseconds at which gossip will pick a random node from the seed list and send a SYN request
comPort : port for the listening UDP socket
debug : flag that will provide debugging messages
debugOutput : if debug is set to true, then this method will be used as a callback with the debug message as the first parameter
config = {
seedList = {'192.168.0.54','192.168.0.55'},
roundInterval = 10000,
comPort = 5000,
debug = true,
debugOutput = function(message) print('Gossip says: '..message); end
}If any of them is not provided, the values will default:
seedList : nil
roundInterval: 10000 (10 seconds)
comPort : 5000
debug : false
debugOutput : print
start()
#### Syntax
gossip.start()Starts gossip, sets the started flag to true and initiates the revision. The revision (generation) main purpose is like a persistent heartbeat, as the heartbeat (measured by uptime in seconds) will obviously revert to 0.
callbackFunction
#### Syntax
gossip.callbackFunction = function(data)
processData(data)
end-- stop the callback
gossip.callbackFunction = nil
If declared, this function will get called every time there is a SYN with new data.
pushGossip()
#### Syntax
gossip.pushGossip(data, [ip])-- remove data
gossip.pushGossip(nil, [ip])
Send a SYN request outside of the normal gossip round. The IP is optional and if none given, it will pick a random node.
!!! note
. By calling pushGossip(nil) you effectively remove the data table from the node's network state and notify other nodes of this.setRevManually()
#### Syntax
gossip.setRevFileValue(number)The only scenario when rev should be set manually is when a new node is added to the network and has the same IP. Having a smaller revision than the previous node with the same IP would make gossip think the data it received is old, thus ignoring it.
!!! noteThe revision file value will only be read when gossip starts and it will be incremented by one.
getNetworkState()
#### Syntax
networkState = gossip.getNetworkState()
print(networkState)The network state can be directly accessed as a Lua table : gossip.networkState or it can be received as a JSON with this method.
#### Returns
JSON formatted string regarding the network state.
Example:
{
"192.168.0.53": {
"state": 3,
"revision": 25,
"heartbeat": 2500,
"extra" : "this is some extra info from node 53"
},
"192.168.0.75": {
"state": 0,
"revision": 4,
"heartbeat": 6500
}
}---
Lua Modules/Hdc1000
HDC1000 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-03-07 | Francesco Truzzi | Francesco Truzzi | hdc1000.lua |
This Lua module provides access to HDC1000 I²C digital humidity and temperature sensor. It should also work with HDC1008 sensor bout this haven't been tested.
!!! note
This module requires i2c C module built into firmware.
Require
HDC1000 = require("HDC1000")Release
HDC1000 = nil
package.loaded["HDC1000"] = nilHDC1000.setup()
Function to setup the HDC1000 sensor.
#### SyntaxHDC1000.setup(drdyn)
#### Parameters
- drdyn: DRDYn pin number. If set to false, this feature will not be used and after each read request a 20ms delay will be added.
#### Returnsnil
#### Example
local sda, scl = 3, 4 -- Pins 3 and 4 will be used
local drdyn = 6 -- Pin 6 will be used to connect with DRDYn pin
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
HDC1000.setup(drdyn)HDC1000.config()
Function to configure various options of HDC1000 sensor.
#### SyntaxHDC1000.config(address, resolution, heater)
#### Parameters
- address: I²C sensor address. Default value is 0x40.
- resolution: Temperature and humidity sensor resolution. Can be set to 14 bits for both temperature and humidity (0x00), 11 bits for temperature (0x40), 11 bits for humidity (0x01) or 8 bits for humidity (0x20). Default value is 0x00.
- heater: Heater setting. 0x20 to enable and 0x00 to disable. Default value is 0x20.
#### Returnsnil
HDC1000.getTemp()
Reads the temperature from HDC1000 sensor.
#### SyntaxHDC1000.getTemp()
#### Parameters
None
#### Returns
Temperature in Celsius degrees.
HDC1000.getHumi()
Reads the humidity value from HDC1000 sensor.
#### SyntaxHDC1000.getHumi()
#### Parameters
None
#### Returns
Humidity in percents.
HDC1000.batteryDead()
Function that checks if voltage of sensor power supply is bellow or above 2.8V.
#### SyntaxHDC1000.batteryDead()
#### Parameters
None
#### Returnstrue if battery voltage is bellow 2.8V, false otherwise.
#### Example
HDC1000 = require("HDC1000")sda = 1
scl = 2
drdyn = false
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
HDC1000.setup(drdyn)
HDC1000.config() -- default values are used if called with no arguments. prototype is config(address, resolution, heater)
print(string.format("Temperature: %.2f °C\nHumidity: %.2f %%", HDC1000.getTemp(), HDC1000.getHumi()))
HDC1000 = nil
package.loaded["HDC1000"] = nil
---
Lua Modules/Httpserver
HTTP Server Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-01-19 | Vladimir Dronnikov | Vladimir Dronnikov | http.lua |
This Lua module provides a simple callback implementation of a HTTP 1.1 server.
Require
httpserver = require("httpserver")Release
httpserver = nil
package.loaded["httpserver"] = nilhttpserver.createServer()
Function to start HTTP server.
#### Syntaxhttpserver.createServer(port, handler(req, res))
#### Parameters
- port: Port number for HTTP server. Most HTTP servers listen at port 80.
- handler: callback function for when HTTP request was made.
#### Returnsnet.server sub module.
#### Notes
Callback function has 2 arguments: req (request) and res (response). The first object holds values:
- conn: net.socket sub module. DO NOT call :on or :send on this
object.
- method: Request method that was used (e.g.POST or GET)
- url: Requested URL
- onheader: assign a function to this value which will be called as soon as HTTP headers like content-type are available.
This handler function has 3 parameters:
- self: req object
- name: Header name. Will allways be lowercase.
- value: Header value
- ondata: assign a function to this value which will be called as soon as body data is available.
This handler function has 2 parameters:
- self: req object
- chunk: Request data. If all data is received there will be one last call with data = nil
The second object holds functions:
- send(self, data, [response_code]): Function to send data to client.
- self: res object
- data: data to send (may be nil)
- response_code: the HTTP response code like 200(default) or 404 (for example) NOTE if there are several calls with response_code given only the first one will be used. Any further codes given will be ignored.
- send_header(self, header_name, header_data): Function to send HTTP headers to client. This function will not be available after data has been sent. (It will be nil.)
- self: res object
- header_name: the HTTP header name
- header_data: the HTTP header data
- finish([data[, response_code]]): Function to finalize connection, optionally sending data and return code.
- data: optional data to send on connection finalizing
- response_code: the HTTP response code like 200(default) or 404 (for example) NOTE if there are several calls with response_code given only the first one will be used. Any further codes given will be ignored.
Full example can be found in http-example.lua
---
Lua Modules/Imap
IMAP Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-03-12 | AllAboutEE | AllAboutEE | imap.lua |
This Lua module provides a simple implementation of an IMAP 4rev1 protocol that can be used to read e-mails.
Require
imap = require("imap.lua")Release
imap = nil
package.loaded["imap"] = nilimap.response_processed()
Function used to check if IMAP command was processed.
#### Syntaximap.response_processed()
#### Parameters
None
#### Returns
The response process status of the last IMAP command sent. If return value is true it means the command was processed.
imap.config()
Initiates the IMAP settings.
#### Syntaximap.config(username, password, tag, [debug])
#### Parameters
- username: IMAP username. For most e-mail providers e-mail address is used as username.
- password: IMAP password.
- tag: IMAP tag. With current implementation any tag like "t1" should work.
- debug: (boolean) if set to true entire conversation between the ESP8266 and IMAP server will be shown. Default setting is false.
#### Returnsnil
imap.login()
Logs into a new email session.
#### Syntaximap.login(socket)
#### Parameters
- socket: IMAP TCP socket object created using net.createConnection
#### Returnsnil
imap.get_most_recent_num()
Function to check the most recent email number. Should only be called after
examine function.#### Syntaximap.get_most_recent_num()
#### Parameters
None
#### Returns
The most recent email number.
imap.examine()
IMAP examines the given mailbox/folder. Sends the IMAP EXAMINE command.
#### Syntaximap.examine(socket, mailbox)
#### Parameters
- socket: IMAP TCP socket object created using net.createConnection
- mailbox: E-mail folder name to examine like example "INBOX"
#### Returnsnil
imap.get_header()
Function that gets the last fetched header field.
#### Syntaximap.get_header()
#### Parameters
None
#### Returns
The last fetched header field.
imap.fetch_header()
Fetches an e-mails header field e.g. SUBJECT, FROM, DATE.
#### Syntaximap.fetch_header(socket, msg_number, field)
#### Parameters
- socket: IMAP TCP socket object created using net.createConnection
- msg_number: The email number to read e.g. 1 will read fetch the latest/newest email
- field: A header field such as SUBJECT, FROM, or DATE
#### Returnsnil
imap.get_body()
Function to get the last email read's body.
#### Syntaximap.get_body()
#### Parameters
None
#### Returns
The last email read's body.
imap.fetch_body_plain_text()
Sends the IMAP command to fetch a plain text version of the email's body.
#### Syntaximap.fetch_body_plain_text(socket, msg_number)
#### Parameters
- socket: IMAP TCP socket object created using net.createConnection
- msg_number: The email number to obtain e.g. 1 will obtain the latest email.
#### Returnsnil
imap.logout()
Sends the IMAP command to logout of the email session.
#### Syntaximap.logout(socket)
#### Parameters
- socket: IMAP TCP socket object created using net.createConnection
#### Returnsnil
#### Example
Example use of imap module can be found in read_email_imap.lua file.
---
Lua Modules/Liquidcrystal
LiquidCrystal Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2019-12-01 | Matsievskiy Sergey | Matsievskiy Sergey | liquidcrystal.lua i2c4bit.lua gpio4bit.lua gpio8bit.lua |
This Lua module provides access to Hitachi HD44780 based LCDs. It supports 4 bit and 8 bit GPIO interface, 4 bit PCF8574 based I²C interface.
!!! note
This module requires bit C module built into firmware. Depending on the interface, gpio or i2c module is also required.
Program example
In this example LED screen is connected using I²C GPIO expander.
Program defines five custom characters and prints text.
backend_meta = require "lc-i2c4bit"
lc_meta = require "liquidcrystal"-- create display object
lc = lc_meta(backend_meta{sda=1, scl=2}, false, true, 20)
backend_meta = nil
lc_meta = nil
-- define custom characters
lc:customChar(0, {0,14,31,31,4,4,5,2})
lc:customChar(1, {4,6,5,5,4,12,28,8})
lc:customChar(2, {14,31,17,17,17,17,17,31})
lc:customChar(3, {14,31,17,17,17,17,31,31})
lc:customChar(4, {14,31,17,17,31,31,31,31})
lc:customChar(5, {14,31,31,31,31,31,31,31})
lc:clear() -- clear display
lc:blink(true) -- enable cursor blinking
lc:home() -- reset cursor position
lc:write("hello", " ", "world") -- write string
lc:cursorMove(1, 2) -- move cursor to second line
lc:write("umbrella", 0, 32, "note", 1) -- mix text strings and characters
lc:cursorMove(1, 3)
lc:write("Battery level ", 2, 3, 4, 5)
lc:home()
lc:blink(false)
for i=1,20 do print(lc:read()) end -- read back first line
lc:home()
for _, d in ipairs(lc:readCustom(0)) do print(d) end -- read back umbrella char
for _, d in ipairs(lc:readCustom(1)) do print(d) end -- read back note char
Require
i2c4bit_meta = require("lc-i2c4bit")
gpio4bit_meta = require("lc-gpio4bit")
gpio8bit_meta = require("lc-gpio8bit")
lc_meta = require("liquidcrystal")Release
package.loaded["lc-i2c4bit"] = nil
package.loaded["lc-gpio4bit"] = nil
package.loaded["lc-gpio8bit"] = nil
package.loaded["liquidcrystal"] = nilInitialization
Liquidcrystal module is initialized using closure, which takes backend object as an argument.
I²C backend
Loading I²C backend module returns initialization closure.
It configures I²C backend and returns backend object.
#### Syntaxfunction({[sda=sda_pin] [, scl=scl_pin] [, busid=id] [, busad=address] [, speed = spd] [, rs = rs_pos] [, rw = rw_pos] [, en = en_pos] [, bl = bl_pos] [, d4 = d4_pos] [, d5 = d5_pos] [, d6 = d6_pos] [, d7 = d7_pos]})
!!! note
In most cases only sda and scl parameters are required
#### Parameters
- sda: I²C data pin. If set to nil, I²C bus initialization step via i2c.setup will be skipped
- scl: I²C clock pin. If set to nil, I²C bus initialization step via i2c.setup will be skipped
- busid: I²C bus ID. Defaults to 0
- busad: chip I²C address. Defaults to 0x27 (default PCF8574 address)
- speed: I²C speed. Defaults to i2c.SLOW
- rs: bit position assigned to RS pin in I²C word. Defaults to 0
- rw: bit position assigned to RW pin in I²C word. Defaults to 1
- en: bit position assigned to EN pin in I²C word. Defaults to 2
- bl: bit position assigned to backlight pin in I²C word. Defaults to 3
- d4: bit position assigned to D4 pin in I²C word. Defaults to 4
- d5: bit position assigned to D5 pin in I²C word. Defaults to 5
- d6: bit position assigned to D6 pin in I²C word. Defaults to 6
- d7: bit position assigned to D7 pin in I²C word. Defaults to 7
#### Returns
- backend object
#### Example
backend_meta = require "lc-i2c4bit"
backend = backend_meta{sda=1, scl=2 ,speed=i2c.FAST}GPIO 4 bit backend
Loading GPIO 4 bit backend module returns initialization closure.
It configures GPIO 4 bit backend and returns backend object.
#### Syntaxfunction({[, rs = rs_pos] [, rw = rw_pos] [, en = en_pos] [, bl = bl_pos] [, d4 = d4_pos] [, d5 = d5_pos] [, d6 = d6_pos] [, d7 = d7_pos]})
#### Parameters
- rs: GPIO pin connected to RS pin. Defaults to 0
- rw: GPIO pin connected to RW pin. If set to nil then busy, position and readChar functions will not be available. Note that RW pin must be pulled to the ground if not connected to GPIO
- en: GPIO pin connected to EN pin. Defaults to 1
- bl: GPIO pin controlling backlight. It is assumed, that high level turns backlight on, low level turns backlight off. If set to nil then backlight function will not be available
- d4: GPIO pin connected to D4 pin. Defaults to 2
- d5: GPIO pin connected to D5 pin. Defaults to 3
- d6: GPIO pin connected to D6 pin. Defaults to 4
- d7: GPIO pin connected to D7 pin. Defaults to 5
#### Returns
- backend object
#### Example
backend_meta = require "lc-gpio4bit"
backend = backend_meta{rs=0, rw=1, en=4, d4=5, d5=6, d6=7, d7=8}GPIO 8 bit backend
Loading GPIO 8 bit backend module returns initialization closure.
It configures GPIO 8 bit backend and returns backend object.
#### Syntaxfunction({[, rs = rs_pos] [, rw = rw_pos] [, en = en_pos] [, bl = bl_pos] [, d0 = d0_pos] [, d1 = d1_pos] [, d2 = d2_pos] [, d3 = d3_pos] [, d4 = d4_pos] [, d5 = d5_pos] [, d6 = d6_pos] [, d7 = d7_pos]})
#### Parameters
- rs: GPIO pin connected to RS pin. Defaults to 0
- rw: GPIO pin connected to RW pin. If set to nil then busy, position and readChar functions will not be available. Note that RW pin must be pulled to the ground if not connected to GPIO
- en: GPIO pin connected to EN pin. Defaults to 1
- bl: GPIO pin controlling backlight. It is assumed, that high level turns backlight on, low level turns backlight off. If set to nil then backlight function will not be available
- d0: GPIO pin connected to D0 pin. Defaults to 2
- d1: GPIO pin connected to D1 pin. Defaults to 3
- d2: GPIO pin connected to D2 pin. Defaults to 4
- d3: GPIO pin connected to D3 pin. Defaults to 5
- d4: GPIO pin connected to D4 pin. Defaults to 6
- d5: GPIO pin connected to D5 pin. Defaults to 7
- d6: GPIO pin connected to D6 pin. Defaults to 8
- d7: GPIO pin connected to D7 pin. Defaults to 9
#### Returns
- backend object
#### Example
backend_meta = require "lc-gpio8bit"
backend = backend_meta{rs=15, rw=2, en=5, d0=23, d1=13, d2=33, d3=32, d4=18, d5=19, d6=21, d7=22}Liquidcrystal initialization
Loading Liquidcrystal module returns initialization closure.
It requires backend object and returns LCD object.
#### Syntaxfunction(backend, onelinemode, eightdotsmode, column_width)
#### Parameters
- backend: backend object
- onelinemode: true to use one line mode, false to use two line mode
- eightdotsmode: true to use 5x8 dot font, false to use 5x10 dot font
- column_width: number of characters in column. Used for offset calculations in function cursorMove. If set to nil, functionality of cursorMove will be limited. For most displays column width is 20 characters
#### Returns
screen object
#### Example
lc_meta = require "liquidcrystal"
lc = lc_meta(backend, true, true, 20)liquidcrystal.autoscroll
Autoscroll text when printing. When turned off, cursor moves and text stays still, when turned on, vice versa.
#### Syntaxliquidcrystal.autoscroll(self, on)
#### Parameters
- self: liquidcrystal instance
- on: true to turn on, false to turn off
#### Returns
- sent data
#### Example
liquidcrystal:autoscroll(true)liquidcrystal.backlight
Control LCDs backlight. When using GPIO backend without
bl argument specification function does nothing.#### Syntaxliquidcrystal.backlight(self, on)
#### Parameters
- self: liquidcrystal instance
- on: true to turn on, false to turn off
#### Returns
- backlight status
#### Example
liquidcrystal:backlight(true)liquidcrystal.blink
Control cursors blink mode.
#### Syntaxliquidcrystal.blink(self, on)
#### Parameters
- self: liquidcrystal instance
- on: true to turn on, false to turn off
#### Returns
- sent data
#### Example
liquidcrystal:blink(true)liquidcrystal.busy
Get busy status of the LCD. When using GPIO backend without
rw argument specification function does nothing.!!! note
At least some HD44780s and/or interfaces have been observed to count polling
the busy flag as grounds for incrementing their position in memory. This is
mysterious, but software should restore the position after observing that the
busy flag is clear.
#### Syntaxliquidcrystal.busy(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- true if device is busy, false if device is ready to receive commands
#### Example
while liquidcrystal:busy() do endliquidcrystal.clear
Clear LCD screen.
#### Syntaxliquidcrystal.clear(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- sent data
#### Example
liquidcrystal:clear()liquidcrystal.cursorLeft
Move cursor one character to the left.
#### Syntaxliquidcrystal.cursorLeft(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- sent data
#### Example
liquidcrystal:cursorLeft()liquidcrystal.cursorMove
Move cursor to position. If
row not specified, move cursor to address col.!!! note
Note that column and row indexes start with 1. However, when omitting row parameter, cursor addresses start with 0.
#### Syntaxliquidcrystal.cursorMove(self, col, row)
#### Parameters
- self: liquidcrystal instance
- col: new cursor position column. If row not specified, new cursor position address
- row: new cursor position row or nil
#### Returns
- sent data
#### Example
liquidcrystal:cursorMove(5, 1)
liquidcrystal:cursorMove(10, 4)
liquidcrystal:cursorMove(21)liquidcrystal.cursor
Control cursors highlight mode.
#### Syntaxliquidcrystal.cursor(self, on)
#### Parameters
- self: liquidcrystal instance
- on: true to turn on, false to turn off
#### Returns
- sent data
#### Example
liquidcrystal:cursor(true)liquidcrystal.cursorRight
Move cursor one character to the right.
#### Syntaxliquidcrystal.cursorRight(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- sent data
#### Example
liquidcrystal:cursorRight()liquidcrystal.customChar
Define new custom char. Up to 8 custom characters with indexes 0 to 7 may be defined in eight dot mode.
They are accessed via
write function by index.In ten dot mode only 4 custom characters may be used.
They are numbered from 0 to 7 with half of them being aliases to each other (0 to 1, 2 to 3 etc).
!!! note
Upon redefinition of a custom character all its instances will be updated automatically.
This function resets cursor position to home if liquidcrystal.position function is not available.
There are web services (1, 2) and desktop applications that help create custom characters.
#### Syntaxliquidcrystal.customChar(self, index, bytes)
#### Parameters
- self: liquidcrystal instance
- index: custom char index in range from 0 to 7
- bytes: array of 8 bytes in eight bit mode or 11 bytes in ten bit mode (eleventh line is a cursor line that can also be used) that defines new char bitmap line by line
#### Returnsnil
#### Example
liquidcrystal:customChar(5, {14,31,31,31,31,31,31,31})
liquidcrystal:write(5)liquidcrystal.display
Turn display on and off. Does not affect display backlight. Does not clear the display.
#### Syntaxliquidcrystal.display(self, on)
#### Parameters
- self: liquidcrystal instance
- on: true to turn on, false to turn off
#### Returns
- sent data
#### Example
liquidcrystal:display(true)liquidcrystal.home
Reset cursor and screen position.
#### Syntaxliquidcrystal.home(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- sent data
#### Example
liquidcrystal:home()liquidcrystal.leftToRight
Print text left to right (default).
#### Syntaxliquidcrystal.leftToRight(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- sent data
#### Example
liquidcrystal:leftToRight()liquidcrystal.position
Get current position of the cursor. Position is 0 indexed. When using GPIO backend without
rw argument specification function does nothing.!!! note
At least some HD44780s and/or interfaces have been observed to count reading
the position as grounds for incrementing their position in memory. This is
mysterious, but software likely intends to restore the position anyway.
#### Syntaxliquidcrystal.position(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- 0 indexed position of the cursor
#### Example
local pos = liquidcrystal:position() -- save position
-- some code
liquidcrystal:cursorMove(pos) -- restore positionliquidcrystal.read
Return current character numerical representation.
When using GPIO backend without
rw argument specification function does nothing.#### Syntaxliquidcrystal.read(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- numerical representation of the current character
#### Example
liquidcrystal:home() -- goto home
local ch = liquidcrystal:read() -- read char
liquidcrystal:cursorMove(1, 2) -- move to the second line
for i=ch,ch+5 do lc:write(i) end -- print 6 chars starting with chliquidcrystal.readCustom
Return custom char byte array.
When using GPIO backend without
rw argument specification function returns zeros.#### Syntaxliquidcrystal.readCustom(self, index)
#### Parameters
- self: liquidcrystal instance
- index: custom char index in range from 0 to 7
#### Returns
- table of size 8 in eight dot mode or 11 in ten dot mode. Each 8 bit number represents a character dot line
#### Example
lc:customChar(0, {0,14,31,31,4,4,5,2}) -- define custom character
for _, d in ipairs(lc:readCustom(0)) do print(d) end -- read it backliquidcrystal.rightToLeft
Print text right to left.
#### Syntaxliquidcrystal.rightToLeft(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- sent data
#### Example
liquidcrystal:rightToLeft()liquidcrystal.scrollLeft
Move text to the left.
#### Syntaxliquidcrystal.scrollLeft(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- sent data
#### Example
liquidcrystal:scrollLeft()liquidcrystal.scrollRight
Move text to the right.
#### Syntaxliquidcrystal.scrollRight(self)
#### Parameters
- self: liquidcrystal instance
#### Returns
- sent data
#### Example
liquidcrystal:scrollRight()liquidcrystal.write
Print text.
#### Syntaxliquidcrystal.write(self, ...)
#### Parameters
- self: liquidcrystal instance
- ...: strings or char codes. For the list of available characters refer to HD44780 datasheet
#### Returnsnil
#### Example
liquidcrystal:write("hello world")
liquidcrystal:write("hello yourself", "!!!", 243, 244)---
Lua Modules/Lm92
LM92 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-05-17 | Levente Tamas | Levente Tamas | lm92.lua |
This Lua module provides access to LM92 I²C ±0.33C 12bit+sign temperature sensor.
!!! note
This module requires i2c C module built into firmware.
Require
lm92 = require("lm92")Release
lm92 = nil
package.loaded["lm92"] = nillm92.setup()
Function used to setup the address for lm92.
#### Syntaxlm92.setup(address)
#### Parameters
- address: I²C address used by LM92. Depends on the connection of A0 and A1 pins. Can be either 0x48, 0x49, 0x4a or 0x4b according to page 9 of LM92 datasheet
#### Returnsnil
#### Example
lm92 = require("lm92")
sda = 3 -- GPIO 0
scl = 4 -- GPIO 2
addr = 0x48
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
lm92.setup(addr)lm92.getTemperature()
Returns the temperature register's content.
#### Syntaxlm92.getTemperature()
#### Parameters
None
#### Returns
Temperature in degree Celsius.
lm92.shutdown()
Makes the chip enter the low power shutdown mode.
#### Syntaxlm92.shutdown()
#### Parameters
None
#### Returnsnil
lm92.wakeup()
Makes the chip exit the low power shutdown mode.
#### Syntaxlm92.wakeup()
#### Parameters
None
#### Returnsnil
lm92.setThyst()
Set hysteresis Temperature.
#### Syntaxlm92.setThyst(htemp)
#### Parameters
- htemp: Hysteresis temperature from 130 to -55 in ĀŗC
#### Returnsnil
lm92.setTcrit()
Set Critical Temperature.
#### Syntaxlm92.setTcrit(ctemp)
#### Parametersctemp: Critical temperature from 130 to -55 in ĀŗC
#### Returnsnil
lm92.setTlow()
Set Low Window Temperature.
#### Syntaxlm92.setTlow(lwtemp)
####Parameters
- lwtemp: Low window temperature from 130 to -55 in ĀŗC
#### Returnsnil
lm92.setThigh()
Set High Window Temperature.
#### Syntaxlm92.setThigh(hwtemp)
#### Parameters
- hwtemp: High window temperature from 130 to -55 in ĀŗC
#### Returnsnil
lm92.getThyst()
Get hysteresis Temperature.
#### Syntaxlm92.getThyst()
#### Parameters
None
#### Returns
Hysteresis Temperature in degree Celsius.
lm92.getTcrit()
Get Critical Temperature.
#### Syntaxlm92.getTcrit()
#### Parameters
None
#### Returns
Critical Temperature in degree Celsius.
lm92.getTlow()
Get Low Window Temperature.
#### Syntaxlm92.getTlow()
#### Parameters
None
#### Returns
Low Window Temperature in degree Celsius.
lm92.getThigh()
Get High Window Temperature.
#### Syntaxlm92.getThigh()
#### Parameters
None
#### Returns
High Window Temperature in degree Celsius.
#### Example
--node.compile("lm92.lua")
lm92 = require("lm92")
sda = 3 -- GPIO 0
scl = 4 -- GPIO 2
addr = 0x48
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
lm92.setup(addr)t = lm92.getTemperature()
print("Got temperature: "..t.." C")
--Seting comparison temperatures
lm92.setThyst(3)
lm92.setTcrit(40.75)
lm92.setTlow(28.5)
lm92.setThigh(31.625)
t = lm92.getThyst()
print("Got hyster: "..t.." C")
t = lm92.getTcrit()
print("Got Crit: "..t.." C")
t = lm92.getTlow()
print("Got Low: "..t.." C")
t = lm92.getThigh()
print("Got High: "..t.." C")
#### TODO:
- add full support of the features, including interrupt and critical alert support
---
Lua Modules/Mcp23008
MCP23008 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-03-02 | AllAboutEE | AllAboutEE | mcp23008.lua |
This Lua module provides access to MCP23008 I²C I/O Expander.
!!! note
This module requires i2c C module built into firmware.
Require
mcp32008 = require("mcp32008")Release
mcp32008 = nil
package.loaded["mcp32008"] = nilmcp32008.begin()
Sets the MCP23008 device address's last three bits.
!!! note
The address is defined as binary 0100[A2][A1][A0] where A2, A1, and A0 are defined by the connection of the pins, e.g. if the pins are connected all to GND then the parameter address will need to be 0x0.
#### Syntaxmcp23008.begin(address, pinSDA, pinSCL, speed)
#### Parameters
- address: The 3 least significant bits (LSB) of the address
- pinSDA: The pin to use for SDA
- pinSCL: The pin to use for SCL
- speed: The speed of the I2C signal
#### Returnsnil
mcp23008.writeGPIO()
Writes a byte of data to the GPIO register.
#### Syntaxmcp23008.writeGPIO(dataByte)
#### Parameters
- dataByte: The byte of data to write
#### Returnsnil
mcp23008.readGPIO()
Reads a byte of data from the GPIO register
#### Syntaxmcp23008.readGPIO()
#### Parameters
None
#### Returns
One byte of data
mcp23008.writeIODIR()
Writes one byte of data to the IODIR register.
#### Syntaxmcp23008.writeIODIR(dataByte)
#### Parameters
- dataByte: The byte of data to write
#### Returnsnil
mcp23008.readIODIR()
Reads a byte from the IODIR register
#### Syntaxmcp23008.readIODIR()
#### Parameters
None
#### Returns
The byte of data in IODIR
mcp23008.writeGPPU()
Writes a byte of data to the GPPU (Pull-UP resistors register)
#### Syntaxmcp23008.writeIODIR(dataByte)
#### Parameters
- dataByte: the value to write to the GPPU register. Each bit in this byte is assigned to an individual GPIO pin
#### Returnsnil
mcp23008.readGPPU()
Reads the GPPU (Pull-UP resistors register) byte
#### Syntaxmcp23008.readGPPU()
#### Parameters
None
#### Returns
The GPPU byte i.e. state of all internal pull-up resistors
#### Notes
Other examples of using this module can be found in mcp23008_buttons.lua and mcp23008_leds.lua files.
---
Lua Modules/Mcp23017
Lua MCP23017 Module for NodeMCU / ESP8266
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2020-04-10 | Marcel P. | Marcel P. | mcp23017.lua |
This Lua module provides access to the MCP23017 I²C I/O Expander.
The MCP23017 is a port expander and provides 16 channels for inputs and outputs.
Up to 8 devices (128 channels) are possible by the configurable address (A0 - A2).
Due to the 16 channels, 2 bytes are required for switching outputs or reading input signals. These are A and B.
A single pin can be set or a whole byte.
The numbering of the individual pins starts at 0 and ends with 7.
The numbers are for each register GPIO A and GPIO B.
!!! important
The module requires i2c and bit C module built into firmware.
Require
mcp = require "mcp23017"Example Script
The example script can be found here
setup()
Configures the address of the module and tests the connection to the i2c bus.
The i2c id is required for an existing i2c interface, alternatively the sda and scl pins can be specified.
Then this function will establish the connection.
Automatically resets the device state (see
mcp23017:reset())#### Syntaxmcp23017:setup(address, i2c_id)
#### Parameter
- address address for MCP23017, default: 0x20 (should be between 0x20 and 0x27)
- i2c_id id for the i2c bus connection (remember to call i2c.setup before)
#### Returntrue if device found, otherwise false.
#### possible Errors
- MCP23017 device on address not found
- MCP23017 address is out of range
#### Example
local mcp23017 = require "mcp23017"local address = 0x20
local cSCL = 1
local cSDA = 2
local i2c_instance = 0
-- setup i2c bus and create instance for mcp23017 (assigned to mcp)
i2c.setup(i2c_instance, cSDA, cSCL, i2c.SLOW)
local mcp = mcp23017(address, i2c_instance)
setMode()
Set the mode of a single channel. This can be OUTPUT or INPUT.
#### Syntaxmcp23017:setMode(register, pin, mode)
#### Parameter
- register the side of channels (GPA or GPB)
- pin the number to be set for the channel (0-15)
- mode the mode for the channel. This can be mcp23017.INPUT or mcp23017.OUTPUT
#### Returntrue, in case of error nil.
#### Example
-- set pin 7 and 8 to output (GPA7 and GPB0) and GPB1 to input
mcp:setMode(mcp.GPA, 7, mcp.OUTPUT)
mcp:setMode(mcp.GPB, 0, mcp.OUTPUT)
mcp:setMode(mcp.GPB, 1, mcp.INPUT)setPin()
Set the state of a single channel. This can be HIGH or LOW.
#### Syntaxmcp23017:setMode(register, pin, state)
#### Parameter
- register the side of channels (GPA or GPB)
- pin the number to be set for the channel (0-15)
- state the state for the channel. This can be mcp23017.HIGH or mcp23017.LOW
#### Returntrue, in case of error nil.
#### Example
-- set pin 7 to high (GPA7)
mcp:setPin(mcp.GPA, 7, mcp.HIGH)
-- set pin 8 to low (GPB0)
mcp:setPin(mcp.GPB, 0, mcp.LOW)getPinState()
get the state for a single channel. This can be HIGH or LOW.
#### Syntaxmcp23017:getPinState(register, pin)
#### Parameter
- register the side of channels (GPA or GPB)
- pin the number for which a state is to be queried (0-15)
#### Returntrue for HIGH, false for LOW, in case of error nil.
#### Example
-- get the state for pin 9 (GPB1)
print(mcp:getPinState(mcp.GPB, 1))reset()
By calling this function, a safe state is established.
All channels are set to input.
This function can be used for a panic program.
#### Syntaxmcp23017:reset()
#### Parameter
None
#### Return
None
#### Example
-- reset the mcp23017 to startup defaults
mcp:reset()setInternalPullUp()
Enable or disable the internal pullup resistors.
#### Syntaxmcp23017:setInternalPullUp(register, byte)
#### Parameter
- register the side of channels (GPA or GPB)
- byte byte to set the pullup resistors
#### Return
None
#### Example
-- enable all pullup resistors for GPA
print(mcp:setInternalPullUp(mcp.GPA, 0xFF))
-- disable all pullup resistors for GPA
print(mcp:setInternalPullUp(mcp.GPA, 0x00))writeIODIR()
Setup the mode of the channels with a whole byte.
#### Syntaxmcp23017:writeIODIR(register, byte)
#### Parameter
- register the side of channels (GPA or GPB)
- byte byte to set the mode for all channels for this register
#### Return
None
#### Example
-- set all GPA to input
print(mcp:writeIODIR(mcp.GPA, 0xFF))
-- set all GPA to output
print(mcp:writeIODIR(mcp.GPA, 0x00))writeGPIO()
Setup the output state of the channels with a whole byte.
#### Syntaxmcp23017:writeGPIO(register, byte)
#### Parameter
- register the side of channels (GPA or GPB)
- byte byte to set the state for all channels for this register
#### Return
None
#### Example
-- set all GPA to HIGH
print(mcp:writeGPIO(mcp.GPA, 0xFF))
-- set all GPA to LOW
print(mcp:writeGPIO(mcp.GPA, 0x00))readGPIO()
Read the input states of the channels with a whole byte.
#### Syntaxmcp23017:readGPIO(register)
#### Parameter
- register the side of channels (GPA or GPB)
#### Return
byte with states
#### Example
-- get states for GPA
print(mcp:readGPIO(mcp.GPA))---
Lua Modules/README
NodeMCU Lua modules directory
Reviewing, hosting and thus potentially maintaining an ever growing list of NodeMCU Lua modules (the ones here) does not scale well for the project team. Instead, we give the community a chance - and the responsibility - to maintain a directory of Lua modules found in the wild through the GitHub wiki.
In the (hopefully not too distant) future, we will request that Lua modules to be hosted _in this repository_ come with a test program in whatever framework we end up adopting.
A module being listed on the wiki does NOT mean the NodeMCU project team endorses it in any way.
ā https://github.com/nodemcu/nodemcu-firmware/wiki/Lua-modules-directory
---
Lua Modules/Redis
Redis Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-02-06 | Vladimir Dronnikov | Vladimir Dronnikov | redis.lua |
This Lua module provides a simple implementation of a Redis client.
Require
redis = dofile("redis.lua")Release
redis = nilredis.connect()
Function used to connect to Redis server.
#### Syntaxredis.connect(host, [port])
#### Parameters
- host Redis host name or address
- port Redis database port. Default value is 6379.
#### Returns
Object with rest of the functions.
!!! important
You need to start calling this connect() function to obtain a Redis object. All other functions are invoked on this object. Note the difference between redis.connect() (single dot) and redis:subscribe() (colon).
redis:subscribe()
Subscribe to a Redis channel.
#### Syntaxredis:subscribe(channel, handler)
#### Parameters
- channel Channel name
- handler Handler function that will be called on new message in subscribed channel
#### Returnsnil
redis:publish()
Publish a message to a Redis channel.
#### Syntaxredis:publish(channel, message)
#### Parameters
- channel Channel name
- message Message to publish
#### Returnsnil
redis:unsubscribe()
Unsubscribes from a channel.
#### Syntaxredis:unsubscribe(channel)
#### Parameters
- channel Channel name to unsubscribe from
#### Returnsnil
redis:close()
Function to close connection to Redis server.
#### Syntaxredis:close()
#### Parameters
None
#### Returnsnil
Example
local redis = dofile("redis.lua").connect(host, port)
redis:publish("chan1", "foo")
redis:subscribe("chan1", function(channel, msg)
print(channel, msg)
end)---
Lua Modules/Telnet
Telnet Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2018-05-24 | Terry Ellison | Terry Ellison | telnet.lua |
The current version of this module exploits the stdin / stdout pipe functionality and
task integration that is now build into the NodeNMCU Lua core.
There are two nice advantages of this core implementation:
- Errors are now written to stdout in a separate task execution.
- The pipes pretty much eliminate UART and telnet overrun.
Both have the same interface if required into the variable telnet
telnet:open()
Open a telnet server based on the provided parameters.
#### Syntax
telnet:open(ssid, pwd, port)
#### Parameters
ssid and password. Strings. SSID and Password for the Wifi network. If these arenil then the wifi is assumed to be configured or auto-configured.
port. Integer TCP listening port for the Telnet service. The default is 2323
#### Returns
Nothing returned (this is evaluated as nil in a scalar context).
telnet:close()
Close a telnet server and release all resources. Also set the variable telnet to nil to fully reference and GC the resources.
#### Syntax
telnet:close()
#### Parameters
None
#### Returns
Nothing returned (this is evaluated as nil in a scalar context).
---
Lua Modules/Yeelink
Yeelink Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-04-14 | Martin Han | Martin Han | yeelink_lib.lua |
This Lua module provides a simple implementation of an Yeelink client.
Require
yeelink = require("yeelink_lib")Release
yeelink = nil
package.loaded["yeelink_lib"] = nilyeelink.init()
Initializes Yeelink client.
#### Syntaxyeelink.init(device, sensor, apikey)
#### Parameters
- device: device number
- sensor: sensor number
- apikey: Yeelink API key string
#### Returns
IP address of api.yeelink.net, if not obtained then false
yeelink.getDNS()
Function to check DNS resolution of
api.yeelink.net status.#### Syntaxyeelink.getDNS()
#### Parameters
None
#### Returns
IP address of api.yeelink.net or nil when name resolution failed.
yeelink.update()
Send data to Yeelink Sever.
#### Syntaxyeelink.update(datapoint)
#### Parameters
- datapoint: Data to send to Yeelink API
#### Returnsnil
#### Notes
Example of using this module can be found in Example_for_Yeelink_Lib.lua file.
---
Modules/Adc
ADC Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2014-12-24 | Zeroday | jmattsson | adc.c|
The ADC module provides access to the in-built ADC.
On the ESP8266 there is only a single-channel, which is multiplexed with the battery voltage. Depending on the setting in the "esp init data" (byte 107) one can either use the ADC to read an external voltage, or to read the system voltage (vdd33), but not both.
Which mode to use the ADC in can be configured via the adc.force_init_mode() function. Note that after switching from one to the other a system restart (e.g. power cycle, reset button, node.restart()) is required before the change takes effect.
adc.force_init_mode()
Checks and if necessary reconfigures the ADC mode setting in the ESP init data block.
####Syntaxadc.force_init_mode(mode_value)
####Parametersmode_value One of adc.INIT_ADC or adc.INIT_VDD33.
####Returns
True if the function had to change the mode, false if the mode was already configured. On a true return the ESP needs to be restarted for the change to take effect.
####Example
-- in you init.lua:
if adc.force_init_mode(adc.INIT_VDD33)
then
node.restart()
return -- don't bother continuing, the restart is scheduled
endprint("System voltage (mV):", adc.readvdd33(0))
####See alsonode.restart()
adc.read()
Samples the ADC.
####Syntaxadc.read(channel)
####Parameterschannel always 0 on the ESP8266
####Returns
the sampled value (number)
If the ESP8266 has been configured to use the ADC for reading the system voltage, this function will always return 65535. This is a hardware and/or SDK limitation.
####Example
val = adc.read(0)adc.readvdd33()
Reads the system voltage.
####Syntaxadc.readvdd33()
####Parameters
none
####Returns
system voltage in millivolts (number)
If the ESP8266 has been configured to use the ADC for sampling the external pin, this function will always return 65535. This is a hardware and/or SDK limitation.
---
Modules/Ads1115
ADS1115 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2017-04-24 | fetchbot | fetchbot | ads1115.c|
This module provides access to the ADS1115 (16-Bit) and ADS1015 (12-Bit) analog-to-digital converters.
Other chips from the same family (ADS1113, ADS1114, ADS1013 and ADS1014) are likely to work. Missing hardware features will be silently ignored.
This module supports multiple devices connected to I²C bus. The devices of different types can be mixed.
The addressing of ADS family allows for maximum of 4 devices connected to the same I²C bus.
!!! caution
The ABSOLUTE MAXIMUM RATINGS for all analog inputs are ā0.3V to VDD+0.3V referred to GND.
ads1115.ads1115()
Registers ADS1115 (ADS1113, ADS1114) device.
#### Syntaxads1115.ADS1115(I2C_ID, I2C_ADDR)
#### Parameters
- I2C_ID - always 0
- ADDRESS - I²C address of a device
* ads1115.ADDR_GND
* ads1115.ADDR_VDD
* ads1115.ADDR_SDA
* ads1115.ADDR_SCL
#### Returns
Registered device object
#### Example
local id, sda, scl = 0, 6, 5
i2c.setup(id, sda, scl, i2c.SLOW)
ads1115.reset()
adc1 = ads1115.ads1115(id, ads1115.ADDR_GND)ads1115.ads1015()
Registers ADS1015 (ADS1013, ADS1014) device.
#### Syntaxads1115.ads1015(I2C_ID, I2C_ADDR)
#### Parameters
- I2C_ID - always 0
- ADDRESS - I²C address of a device
* ads1115.ADDR_GND
* ads1115.ADDR_VDD
* ads1115.ADDR_SDA
* ads1115.ADDR_SCL
#### Returns
Registered device object
#### Example
local id, sda, scl = 0, 6, 5
i2c.setup(id, sda, scl, i2c.SLOW)
ads1115.reset()
adc1 = ads1115.ads1015(id, ads1115.ADDR_VDD)
adc2 = ads1115.ads1115(id, ads1115.ADDR_SDA)ads1115.reset()
Reset all devices connected to I²C interface.
Syntax
ads1115.reset()
#### Parameters
none
#### Returnsnil
#### Example
local id, alert_pin, sda, scl = 0, 7, 6, 5
i2c.setup(id, sda, scl, i2c.SLOW)
ads1115.reset()ADS Device
ads1115.device:read()
Gets the result stored in the register of a previously issued conversion, e.g. in continuous mode or with a conversion ready interrupt.
#### Syntaxvolt, volt_dec, raw, sign = device:read()
#### Parameters
none
#### Returns
- volt voltage in mV (see note below)
- volt_dec voltage decimal in uV (see note below)
- adc raw adc register value
- sign sign of the result (see note below)
!!! note
If using float firmware then volt is a floating point number, volt_dec and sign are nil. On an integer firmware, the final value has to be concatenated from volt, volt_dec and sign. On integer firmware volt and volt_dec are always positive, sign can be -1, 0, 1.
#### Example
local id, alert_pin, sda, scl = 0, 7, 6, 5
i2c.setup(id, sda, scl, i2c.SLOW)
ads1115.reset()
adc1 = ads1115.ads1115(id, ads1115.ADDR_GND)-- continuous mode
adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.CONTINUOUS)
-- read adc result with read()
volt, volt_dec, adc, sign = ads1:read()
print(volt, volt_dec, adc, sign)
-- comparator
adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.CONTINUOUS, ads1115.COMP_1CONV, 1000, 2000)
local function comparator(level, when)
-- read adc result with read() when threshold reached
gpio.trig(alert_pin)
volt, volt_dec, adc, sign = adc1:read()
print(volt, volt_dec, adc, sign)
end
gpio.mode(alert_pin, gpio.INT)
gpio.trig(alert_pin, "both", comparator)
-- read adc result with read()
volt, volt_dec, adc, sign = ads1115:read()
print(volt, volt_dec, adc, sing)
-- format value in int build
if sign then
-- int build
print(string.format("%s%d.%03d mV", sign >= 0 and "+" or "-", volt, volt_dec))
else
-- float build
-- just use V as it is
end
ads1115.device:setting()
Configuration settings for the ADC.
#### Syntaxdevice:setting(GAIN, SAMPLES, CHANNEL, MODE[, CONVERSION_RDY][, COMPARATOR, THRESHOLD_LOW, THRESHOLD_HI[,COMP_MODE]])
#### Parameters
- GAIN Programmable gain amplifier
* ads1115.GAIN_6_144V 2/3x Gain
* ads1115.GAIN_4_096V 1x Gain
* ads1115.GAIN_2_048V 2x Gain
* ads1115.GAIN_1_024V 4x Gain
* ads1115.GAIN_0_512V 8x Gain
* ads1115.GAIN_0_256V 16x Gain
- SAMPLES Data rate in samples per second
* ads1115.DR_8SPS ADS1115 only
* ads1115.DR_16SPS ADS1115 only
* ads1115.DR_32SPS ADS1115 only
* ads1115.DR_64SPS ADS1115 only
* ads1115.DR_128SPS
* ads1115.DR_250SPS
* ads1115.DR_475SPS ADS1115 only
* ads1115.DR_490SPS ADS1015 only
* ads1115.DR_860SPS ADS1115 only
* ads1115.DR_920SPS ADS1015 only
* ads1115.DR_1600SPS ADS1015 only
* ads1115.DR_2400SPS ADS1015 only
* ads1115.DR_3300SPS ADS1015 only
- CHANNEL Input multiplexer for single-ended or differential measurement
* ads1115.SINGLE_0 channel 0 to GND
* ads1115.SINGLE_1 channel 1 to GND
* ads1115.SINGLE_2 channel 2 to GND
* ads1115.SINGLE_3 channel 3 to GND
* ads1115.DIFF_0_1 channel 0 to 1
* ads1115.DIFF_0_3 channel 0 to 3
* ads1115.DIFF_1_3 channel 1 to 3
* ads1115.DIFF_2_3 channel 2 to 3
- MODE Device operating mode
* ads1115.SINGLE_SHOT single-shot mode
* ads1115.CONTINUOUS continuous mode
- CONVERSION_RDY Number of conversions after conversion ready asserts (optional)
* ads1115.CONV_RDY_1
* ads1115.CONV_RDY_2
* ads1115.CONV_RDY_4
- COMPARATOR Number of conversions after comparator asserts (optional)
* ads1115.COMP_1CONV
* ads1115.COMP_2CONV
* ads1115.COMP_4CONV
- THRESHOLD_LOW
* 0 - + GAIN_MAX in mV for single-ended inputs
* - GAIN_MAX - + GAIN_MAX in mV for differential inputs
- THRESHOLD_HI
* 0 - + GAIN_MAX in mV for single-ended inputs
* - GAIN_MAX - + GAIN_MAX in mV for differential inputs
- COMP_MODE Comparator mode
* ads1115.CMODE_TRAD traditional comparator mode (with hysteresis)
* ads1115.CMODE_WINDOW window comparator mode
note: Comparator and conversion ready are always configured to non-latching, active low.
#### Returnsnil
#### Example
local id, sda, scl = 0, 6, 5
i2c.setup(id, sda, scl, i2c.SLOW)
ads1115.reset()
adc1 = ads1115.ads1015(id, ads1115.ADDR_GND)adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_3300SPS, ads1115.SINGLE_0, ads1115.SINGLE_SHOT)
ads1115.device:startread()
Starts the ADC reading for single-shot mode and after the conversion is done it will invoke an optional callback function in which the ADC conversion result can be obtained.
#### Syntaxdevice:startread([CALLBACK])
#### Parameters
- CALLBACK callback function which will be invoked after the adc conversion is done
* function(volt, volt_dec, adc, sign) end
#### Returns
- nil
#### Example
local id, alert_pin, sda, scl = 0, 7, 6, 5
i2c.setup(id, sda, scl, i2c.SLOW)
ads1115.reset()
adc1 = ads1115.ads1115(id, ads1115.ADDR_VDD)-- single shot
adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.SINGLE_SHOT)
-- start adc conversion and get result in callback after conversion is ready
adc1:startread(function(volt, volt_dec, adc, sign) print(volt, volt_dec, adc, sign) end)
-- conversion ready
adc1:setting(ads1115.GAIN_6_144V, ads1115.DR_128SPS, ads1115.SINGLE_0, ads1115.SINGLE_SHOT, ads1115.CONV_RDY_1)
local function conversion_ready(level, when)
gpio.trig(alert_pin)
volt, volt_dec, adc, sign = adc1:read()
print(volt, volt_dec, adc, sign)
end
gpio.mode(alert_pin, gpio.INT)
gpio.trig(alert_pin, "down", conversion_ready)
-- start conversion and get result with read() after conversion ready pin asserts
adc1:startread()
---
Modules/Adxl345
ADXL345 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2016-04-08 | Jason Schmidlapp | Jason Schmidlapp | adxl345.c|
This module provides access to the ADXL345 triple axis accelerometer.
adxl345.read()
Samples the sensor and returns X,Y and Z data from the accelerometer.
#### Syntaxadxl345.read()
#### Returns
X,Y,Z data (integers)
#### Example
local sda, scl = 1, 2
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
adxl345.setup()
local x,y,z = adxl345.read()
print(string.format("X = %d, Y = %d, Z = %d", x, y, z))adxl345.setup()
Initializes the module.
#### Syntaxadxl345.setup()
#### Parameters
None
#### Returnsnil
---
Modules/Am2320
AM2320 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2016-02-14 | Henk Vergonet | Henk Vergonet | am2320.c|
This module provides access to the AM2320 humidity and temperature sensor, using the i2c interface.
!!! caution
This code is licensed under GPL by its author. Any binaries that include this module becomes subject to the GPL, requiring anyone who ships them to also ship source.
am2320.read()
Samples the sensor and returns the relative humidity in % and temperature in celsius, as an integer multiplied with 10.
#### Syntaxam2320.read()
#### Returns
- relative humidity percentage multiplied with 10 (integer)
- temperature in celcius multiplied with 10 (integer)
#### Example
sda, scl = 1, 2
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
am2320.setup()
rh, t = am2320.read()
print(string.format("RH: %s%%", rh / 10))
print(string.format("Temperature: %s degrees C", t / 10))am2320.setup()
Initializes the module. Returns model, version, serial but is seams these where all zero on my model.
#### Syntaxmodel, version, serial = am2320.setup()
#### Parameters
None
#### Returns
- model 16 bits number of model
- version 8 bits version number
- serial 32 bits serial number
Note: I have only observed values of 0 for all of these, maybe other sensors return more sensible readings.
---
Modules/Apa102
APA102 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2016-01-26 | Robert Foss| Robert Foss| apa102.c|
This module provides Lua access to APA102 RGB LEDs which are similar in function to the common WS2812 addressable LEDs.
DotStar LEDs are 5050-sized LEDs with an embedded micro controller inside the LED. You can set the color/brightness of each LED to 24-bit color (8 bits each red green and blue). Each LED acts like a shift register, reading incoming color data on the input pins, and then shifting the previous color data out on the output pin. By sending a long string of data, you can control an infinite number of LEDs, just tack on more or cut off unwanted LEDs at the end.
source: Adafruit
!!! caution
This module has an _optional_ dependency to the pixbuf module i.e. it can work without. However, if you compile the firmware without pixbuf the respective features will be missing from this module.
apa102.write()
Send ABGR data in 8 bits to a APA102 chain.
#### Syntaxapa102.write(data_pin, clock_pin, string)
#### Parameters
- data_pin any GPIO pin 0, 1, 2, ...
- clock_pin any GPIO pin 0, 1, 2, ...
- data payload to be sent to one or more APA102 LEDs.
It may be a pixbuf with four channels or a string,
composed from a ABGR quadruplet per element:
- A1 the first pixel's Intensity channel (0-31)
- B1 the first pixel's Blue channel (0-255)<br />
- G1 the first pixel's Green channel (0-255)
- R1 the first pixel's Red channel (0-255)
... You can connect a lot of APA102 ...
- A2, B2, G2, R2 are the next APA102s Intensity, Blue, Green and Red channel parameters
#### Returnsnil
#### Example 1
a = 31
b = 0
g = 0
r = 255
leds_abgr = string.char(a, b, g, r, a, b, g, r)
apa102.write(2, 3, leds_abgr) -- turn two APA102s to red, connected to data_pin 2 and clock_pin 3#### Example 2
-- set the first 30 leds to red
apa102.write(2, 3, string.char(31, 255, 0, 0):rep(30))---
Modules/Bit
bit Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2014-12-24 | https://github.com/LuaDist/bitlib, Zeroday | Zeroday | bit.c|
Bit manipulation support, on 32bit integers.
bit.arshift()
Arithmetic right shift a number equivalent to
value >> shift in C.#### Syntaxbit.arshift(value, shift)
#### Parameters
- value the value to shift
- shift positions to shift
#### Returns
the number shifted right (arithmetically)
#### Example
bit.arshift(3, 1) -- returns 1
-- Using a 4 bits representation: 0011 >> 1 == 0001bit.band()
Bitwise AND, equivalent to val1 & val2 & ... & valn in C.
#### Syntaxbit.band(val1, val2 [, ... valn])
#### Parameters
- val1 first AND argument
- val2 second AND argument
- ...valn ...nth AND argument
#### Returns
the bitwise AND of all the arguments (number)
Example
bit.band(3, 2) -- returns 2
-- Using a 4 bits representation: 0011 & 0010 == 0010bit.bit()
Generate a number with a 1 bit (used for mask generation). Equivalent to 1 << position in C.
#### Syntaxbit.bit(position)
#### Parametersposition position of the bit that will be set to 1
#### Returns
a number with only one 1 bit at position (the rest are set to 0)
Example
bit.bit(4) -- returns 16bit.bnot()
Bitwise negation, equivalent to ~value in C.
#### Syntaxbit.bnot(value)
#### Parametersvalue the number to negate
#### Returns
the bitwise negated value of the number
bit.bor()
Bitwise OR, equivalent to
val1 | val2 | ... | valn in C.#### Syntaxbit.bor(val1, val2 [, ... valn])
#### Parameters
- val1 first OR argument.
- val2 second OR argument.
- ...valn ...nth OR argument
#### Returns
the bitwise OR of all the arguments (number)
Example
bit.bor(3, 2) -- returns 3
-- Using a 4 bits representation: 0011 | 0010 == 0011bit.bxor()
Bitwise XOR, equivalent to val1 ^ val2 ^ ... ^ valn in C.
#### Syntaxbit.bxor(val1, val2 [, ... valn])
#### Parameters
- val1 first XOR argument
- val2 second XOR argument
- ...valn ...nth XOR argument
#### Returns
the bitwise XOR of all the arguments (number)
Example
bit.bxor(3, 2) -- returns 1
-- Using a 4 bits representation: 0011 ^ 0010 == 0001bit.clear()
Clear bits in a number.
#### Syntaxbit.clear(value, pos1 [, ... posn])
#### Parameters
- value the base number
- pos1 position of the first bit to clear
- ...posn position of thet nth bit to clear
#### Returns
the number with the bit(s) cleared in the given position(s)
Example
bit.clear(3, 0) -- returns 2bit.isclear()
Test if a given bit is cleared.
#### Syntaxbit.isclear(value, position)
#### Parameters
- value the value to test
- position bit position to test
#### Returns
true if the bit at the given position is 0, false otherwise
Example
bit.isclear(2, 0) -- returns truebit.isset()
Test if a given bit is set.
#### Syntaxbit.isset(value, position)
#### Parameters
- value the value to test
- position bit position to test
#### Returns
true if the bit at the given position is 1, false otherwise
Example
bit.isset(2, 0) -- returns falsebit.lshift()
Left-shift a number, equivalent to
value << shift in C.#### Syntaxbit.lshift(value, shift)
#### Parameters
- value the value to shift
- shift positions to shift
#### Returns
the number shifted left
Example
bit.lshift(2, 2) -- returns 8
-- Using a 4 bits representation: 0010 << 2 == 1000bit.rshift()
Logical right shift a number, equivalent to ( unsigned )value >> shift in C.
#### Syntaxbit.rshift(value, shift)
#### Parameters
- value the value to shift.
- shift positions to shift.
#### Returns
the number shifted right (logically)
Example
bit.rshift(2, 1) -- returns 1
-- Using a 4 bits representation: 0010 >> 1 == 0001bit.set()
Set bits in a number.
#### Syntaxbit.set(value, pos1 [, ... posn ])
#### Parameters
- value the base number.
- pos1 position of the first bit to set.
- ...posn position of the nth bit to set.
#### Returns
the number with the bit(s) set in the given position(s)
Example
bit.set(2, 0) -- returns 3---
Modules/Bloom
Bloom Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2017-11-13 | Philip Gladstone | Philip Gladstone | bloom.c|
This module implements a Bloom filter. This is a probabilistic data structure that is used to test for set membership. There are two operations -- add and check that allow
arbitrary strings to be added to the set or tested for set membership. Since this is a probabilistic data structure, the answer returned can be incorrect. However,
if the string is a member of the set, then the check operation will always return true.
bloom.create()
Create a filter object.
#### Syntaxbloom.create(elements, errorrate)
#### Parameters
- elements The largest number of elements to be added to the filter.
- errorrate The error rate (the false positive rate). This is represented as n where the false positive rate is 1 / n. This is the maximum rate of check returning true when the string is not in the set.
#### Returns
A filter object.
#### Example
filter = bloom.create(10000, 100) -- this will use around 11kB of memoryfilter:add()
Adds a string to the set and returns an indication of whether the string was already present.
#### Syntaxfilter:add(string)
#### Parameters
- string The string to be added to the filter set.
#### Returnstrue if the string was already present in the filter. false otherwise.
#### Example
if filter:add("apple") then
print ("Seen an apple before!")
else
print ("Noted that the first apple has been seen")
endfilter:check()
Checks to see if a string is present in the filter set.
#### Syntaxpresent = filter:check(string)
#### Parameters
- string The string to be checked for membership in the set.
#### Returnstrue if the string was already present in the filter. false otherwise.
#### Example
if filter:check("apple") then
print ("Seen an apple before!")
endfilter:reset()
Empties the filter.
#### Syntaxfilter:reset()
#### Returns
Nothing
#### Example
filter:reset()filter:info()
Get some status information on the filter.
#### Syntaxbits, fns, occupancy, fprate = filter:info()
#### Returns
- bits The number of bits in the filter.
- fns The number of hash functions in use.
- occupancy The number of bits set in the filter.
- fprate The approximate chance that the next check will return true when it should return false. This is represented as the inverse of the probability -- i.e. as the n in 1-in-n chance. This value is limited to 1,000,000.
#### Example
bits, fns, occupancy, fprate = filter:info()---
Modules/Bme280
BME280 module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2016-02-21 | vsky279 | vsky279 | bme280.c|
This module provides a simple interface to BME280/BMP280 temperature/air presssure/humidity sensors (Bosch Sensortec).
!!! caution
Note that you must call setup() before you can start reading values! Furthermore, there has to be a variable delay between some tens to hundreds of milliseconds between setup() and reading measurements. Instead of using a fixed delay you might also poll the sensor until data is delivered e.g. humi() not returning nil anymore.
bme280.altitude()
For given air pressure and sea level air pressure returns the altitude in meters as an integer multiplied with 100, i.e. altimeter function.
#### Syntaxbme280.altitude(P, QNH)
#### Parameters
- P measured pressure
- QNH current sea level pressure
#### Returns
altitude in meters of measurement point
bme280.baro()
Reads the sensor and returns the air pressure in hectopascals as an integer multiplied with 1000 or nil when readout is not successful.
Current temperature is needed to calculate the air pressure so temperature reading is performed prior reading pressure data. Second returned variable is therefore current air temperature.
#### Syntaxbme280.baro()
#### Parameters
none
#### Returns
- P air pressure in hectopascals multiplied by 1000
- T temperature in celsius as an integer multiplied with 100
bme280.dewpoint()
For given temperature and relative humidity returns the dew point in celsius as an integer multiplied with 100.
#### Syntaxbme280.dewpoint(H, T)
#### Parameters
- H relative humidity in percent multiplied by 1000.
- T temperate in celsius multiplied by 100.
#### Returns
dew point in celsisus
bme280.humi()
Reads the sensor and returns the air relative humidity in percents as an integer multiplied with 100 or nil when readout is not successful.
Current temperature is needed to calculate the relative humidity so temperature reading is performed prior reading pressure data. Second returned variable is therefore current temperature.
#### Syntaxbme280.humi()
#### Parameters
none
#### Returns
- H last relative humidity reading in % times 1000
- T temperature in celsius as an integer multiplied with 100
bme280.qfe2qnh()
For given altitude converts the air pressure to sea level air pressure.
#### Syntaxbme280.qfe2qnh(P, altitude)
#### Parameters
- P measured pressure
- altitude altitude in meters of measurement point
#### Returns
sea level pressure
bme280.read()
Reads the sensor and returns the temperature, the air pressure, the air relative humidity and
#### Syntaxbme280.read([altitude])
#### Parameters
- (optional) altitude- altitude in meters of measurement point. If provided also the air pressure converted to sea level air pressure is returned.
#### Returns
- T temperature in celsius as an integer multiplied with 100
- P air pressure in hectopascals multiplied by 1000
- H relative humidity in percent multiplied by 1000
- QNH air pressure in hectopascals multiplied by 1000 converted to sea level
Any of these variables is nil if the readout of given measure was not successful.
bme280.startreadout()
Starts readout (turns the sensor into forced mode). After the readout the sensor turns to sleep mode.
#### Syntaxbme280.startreadout(delay, callback)
#### Parameters
- delay sets sensor to forced mode and calls the callback (if provided) after given number of milliseconds. For 0 the default delay is set to 113ms (sufficient time to perform reading for oversampling settings 16x). For different oversampling setting please refer to BME280 Final Datasheet - Appendix B: Measurement time and current calculation.
- callback if provided it will be invoked after given delay. The sensor reading should be finalized by then so.
#### Returnsnil
bme280.setup()
Initializes module. Initialization is mandatory before read values.
#### Syntax
bme280.setup([temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter])
#### Parameters
- (optional) temp_oss - Controls oversampling of temperature data. Default oversampling is 16x.
- (optional) press_oss - Controls oversampling of pressure data. Default oversampling is 16x.
- (optional) humi_oss - Controls oversampling of humidity data. Default oversampling is 16x
- (optional) sensor_mode - Controls the sensor mode of the device. Default sensor more is normal.
- (optional) inactive_duration - Controls inactive duration in normal mode. Default inactive duration is 20ms.
- (optional) IIR_filter - Controls the time constant of the IIR filter. Default filter coefficient is 16.
- (optional) cold_start - If 0 then the BME280 chip is not initialised. Useful in a battery operated setup when the ESP deep sleeps and on wakeup needs to initialise the driver (the module) but not the chip itself. The chip was kept powered (sleeping too) and is holding the latest reading that should be fetched quickly before another reading starts (bme280.startreadout()). By default the chip is initialised.
|temp_oss, press_oss, humi_oss|Data oversampling|
|-----|-----------------|
|0|Skipped (output set to 0x80000)|
|1|oversampling Ć1|
|2|oversampling Ć2|
|3|oversampling Ć4|
|4|oversampling Ć8|
|5|oversampling Ć16|
|sensor_mode|Sensor mode|
|-----|-----------------|
|0|Sleep mode|
|1 and 2|Forced mode|
|3|Normal mode|
Using forced mode is recommended for applications which require low sampling rate or hostbased synchronization. The sensor enters into sleep mode after a forced readout. Please refer to BME280 Final Datasheet for more details.
|inactive_duration|t standby (ms)|
|-----|-----------------|
|0|0.5|
|1|62.5|
|2|125|
|3|250|
|4|500|
|5|1000|
|6|10|
|7|20|
|IIR_filter|Filter coefficient |
|-----|-----------------|
|0|Filter off|
|1|2|
|2|4|
|3|8|
|4|16|
#### Returnsnil if initialization has failed (no sensor connected?), 2 if sensor is BME280, 1 if sensor is BMP280
#### Example
alt=320 -- altitude of the measurement placesda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
bme280.setup()
P, T = bme280.baro()
print(string.format("QFE=%d.%03d", P/1000, P%1000))
-- convert measure air pressure to sea level pressure
QNH = bme280.qfe2qnh(P, alt)
print(string.format("QNH=%d.%03d", QNH/1000, QNH%1000))
H, T = bme280.humi()
local Tsgn = (T < 0 and -1 or 1); T = Tsgn*T
print(string.format("T=%s%d.%02d", Tsgn<0 and "-" or "", T/100, T%100))
print(string.format("humidity=%d.%03d%%", H/1000, H%1000))
D = bme280.dewpoint(H, T)
local Dsgn = (D < 0 and -1 or 1); D = Dsgn*D
print(string.format("dew_point=%s%d.%02d", Dsgn<0 and "-" or "", D/100, D%100))
-- altimeter function - calculate altitude based on current sea level pressure (QNH) and measure pressure
P = bme280.baro()
curAlt = bme280.altitude(P, QNH)
local curAltsgn = (curAlt < 0 and -1 or 1); curAlt = curAltsgn*curAlt
print(string.format("altitude=%s%d.%02d", curAltsgn<0 and "-" or "", curAlt/100, curAlt%100))
Or simpler and more efficient
alt=320 -- altitude of the measurement placesda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
bme280.setup()
T, P, H, QNH = bme280.read(alt)
local Tsgn = (T < 0 and -1 or 1); T = Tsgn*T
print(string.format("T=%s%d.%02d", Tsgn<0 and "-" or "", T/100, T%100))
print(string.format("QFE=%d.%03d", P/1000, P%1000))
print(string.format("QNH=%d.%03d", QNH/1000, QNH%1000))
print(string.format("humidity=%d.%03d%%", H/1000, H%1000))
D = bme280.dewpoint(H, T)
local Dsgn = (D < 0 and -1 or 1); D = Dsgn*D
print(string.format("dew_point=%s%d.%02d", Dsgn<0 and "-" or "", D/100, D%100))
-- altimeter function - calculate altitude based on current sea level pressure (QNH) and measure pressure
P = bme280.baro()
curAlt = bme280.altitude(P, QNH)
local curAltsgn = (curAlt < 0 and -1 or 1); curAlt = curAltsgn*curAlt
print(string.format("altitude=%s%d.%02d", curAltsgn<0 and "-" or "", curAlt/100, curAlt%100))
Use bme280.setup(1, 3, 0, 3, 0, 4) for "game mode" - Oversampling settings pressure Ć4, temperature Ć1, humidity Ć0, sensor mode: normal mode, inactive duration = 0.5 ms, IIR filter settings filter coefficient 16.
Example of readout in forced mode (asynchronous)
sda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
bme280.setup(nil, nil, nil, 0) -- initialize to sleep mode
bme280.startreadout(0, function ()
T, P = bme280.read()
local Tsgn = (T < 0 and -1 or 1); T = Tsgn*T
print(string.format("T=%s%d.%02d", Tsgn<0 and "-" or "", T/100, T%100))
end)bme280.temp()
Reads the sensor and returns the temperature in celsius as an integer multiplied with 100.
#### Syntaxbme280.temp()
#### Parameters
none
#### Returns
- T temperature in celsius as an integer multiplied with 100 or nil when readout is not successful
- t_fine temperature measure used in pressure and humidity compensation formulas (generally no need to use this value)
---
Modules/Bme280 Math
BME280_math module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2016-02-21 | vsky279 | vsky279 | bme280_math.c|
This module provides calculation routines for BME280/BMP280 temperature/air presssure/humidity sensors (Bosch Sensortec). Communication with the sensor is ensured by Lua code through I2C or SPI interface. Read registers are passed to the module to calculate measured values.
See bme280 Lua module for examples.
bme280_math.altitude()
For given air pressure (called QFE in aviation - see wiki QNH article) and sea level air pressure returns the altitude in meters, i.e. altimeter function.
#### Syntaxbme280_math.altitude([self], P, QNH)
#### Parameters
- (optional) self userdata or table structure so that the function can be directly called as object method, parameter is ignored in the calculation
- P measured pressure
- QNH current sea level pressure
#### Returns
altitude in meters of measurement point
bme280_math.dewpoint()
For given temperature and relative humidity returns the dew point in celsius.
#### Syntaxbme280_math.dewpoint([self], H, T)
#### Parameters
- (optional) self userdata or table structure so that the function can be directly called as object method, parameter is ignored in the calculation
- H relative humidity in percent (100 means 100%)
- T temperate in celsius
#### Returns
dew point in celsisus
bme280_math.qfe2qnh()
For given altitude converts the air pressure to sea level air pressure (QNH).
#### Syntaxbme280_math.qfe2qnh([self], P, altitude)
#### Parameters
- (optional) self userdata or table structure so that the function can be directly called as object method, parameter is ignored in the calculation
- P measured pressure
- altitude altitude in meters of measurement point
#### Returns
sea level pressure
bme280_math.read()
Reads the sensor and returns the temperature, the air pressure, the air relative humidity and see level air pressure when altitude is specified.
#### Syntaxbme280_math.read(bme280sensor, registers, [altitude])
#### Parameters
- bme280sensor - BME280 sensor user data returned by bme280_math.setup()
- registers - string of 8 bytes (chars) registers read from BME280_REGISTER_PRESS
- (optional) altitude- altitude in meters of measurement point. If provided also the air pressure converted to sea level air pressure is returned.
#### Returns
- T temperature in celsius
- P air pressure in hectopascals
- H relative humidity in percent
- (optional) QNH air pressure in hectopascals
Returns nil if the conversion is not successful.
bme280_math.setup()
Initializes module. Initialization is mandatory before read values.
#### Syntax
bme280_math.setup(registers, [temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter])
#### Parameters
- registers - String of configuration registers read from the BME280 sensor. It consists of 6 bytes (chars) of BME280_REGISTER_DIG_T, 18 bytes (chars) BME280_REGISTER_DIG_P and optional (not present for BMP280 sensor) 8 bytes (chars) of BME280_REGISTER_DIG_H1 (1 byte) and BME280_REGISTER_DIG_H2 (7 bytes)
- (optional) temp_oss - Controls oversampling of temperature data. Default oversampling is 16x.
- (optional) press_oss - Controls oversampling of pressure data. Default oversampling is 16x.
- (optional) humi_oss - Controls oversampling of humidity data. Default oversampling is 16x
- (optional) sensor_mode - Controls the sensor mode of the device. Default sensor more is normal.
- (optional) inactive_duration - Controls inactive duration in normal mode. Default inactive duration is 20ms.
- (optional) IIR_filter - Controls the time constant of the IIR filter. Default filter coefficient is 16.
|temp_oss, press_oss, humi_oss|Data oversampling|
|-----|-----------------|
|0|Skipped (output set to 0x80000)|
|1|oversampling Ć1|
|2|oversampling Ć2|
|3|oversampling Ć4|
|4|oversampling Ć8|
|5|oversampling Ć16|
|sensor_mode|Sensor mode|
|-----|-----------------|
|0|Sleep mode|
|1 and 2|Forced mode|
|3|Normal mode|
Using forced mode is recommended for applications which require low sampling rate or hostbased synchronization. The sensor enters into sleep mode after a forced readout. Please refer to BME280 Final Datasheet for more details.
|inactive_duration|t standby (ms)|
|-----|-----------------|
|0|0.5|
|1|62.5|
|2|125|
|3|250|
|4|500|
|5|1000|
|6|10|
|7|20|
|IIR_filter|Filter coefficient |
|-----|-----------------|
|0|Filter off|
|1|2|
|2|4|
|3|8|
|4|16|
#### Returns
- bme280sensor user data (nil if initialization has failed)
- config 3 (2 for BME280) field table with configuration parameters to be written to registers BME280_REGISTER_CONFIG, BME280_REGISTER_CONTROL_HUM, BME280_REGISTER_CONTROL consecutively
#### Example
See bme280 Lua module documentation.
BME280 (selected) registers
| name | address |
|-------|----------|
| BME280_REGISTER_CONTROL | 0xF4 |
| BME280_REGISTER_CONTROL_HUM | 0xF2 |
| BME280_REGISTER_CONFIG| 0xF5 |
| BME280_REGISTER_CHIPID | 0xD0 |
| BME280_REGISTER_DIG_T | 0x88 (0x88-0x8D (6)) |
| BME280_REGISTER_DIG_P | 0x8E (0x8E-0x9F (18)) |
| BME280_REGISTER_DIG_H1 | 0xA1 |
| BME280_REGISTER_DIG_H2 | 0xE1 (0xE1-0xE7 (7)) |
| BME280_REGISTER_PRESS | 0xF7 (0xF7-0xF9 (8)) |
---
Modules/Bme680
BME680 module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2017-10-28 | vsky279 | vsky279 | bme680.c|
This module provides a simple interface to BME680 temperature/air presssure/humidity sensors/air quality sensor (Bosch Sensortec). Compared to the BME280 module the sensor does not support automatic mode which means that it can be setup to perform regular measurements. Every measurement has to be triggered manually.
In order to measure the air quality the sensor needs to be heated first. In the example provided by the manufacturer the sensor is heated to 300 degrees centigrade for a period of 200 ms and then the measurement is taken. These values are taken as default values in this implementation. I have not tested the impact of different temperatures and heating times on the measurement.
This module is able to measure the gas resistance (see Bosch's datasheet). The gas resistance is not the IAQ (Indoor Air Quality) Index. But apparently it can be used as some proxy. The value still should somehow reflect the air quality. It seems that the higher value the air quality is better.
The algorithm for IAQ calculation from the gas restistances (probably measured at different temperatures) is not publicly available. Bosch says that at this point of time the calculations for the Indoor Air Quality index are offered only as a pre-compiled library (see discussion here: BoschSensortec/BME680_driver#6). It is available as the BSEC Library.
The algorithm is implemented in the library bsec/algo/bin/ESP8266/libalgobsec.a. Unfortunately I did not even manage to run the Bosch BSEC example on ESP8266 using this library.
bme680.altitude()
For given air pressure and sea level air pressure returns the altitude in meters as an integer multiplied with 100, i.e. altimeter function.
#### Syntaxbme680.altitude(P, QNH)
#### Parameters
- P measured pressure
- QNH current sea level pressure
#### Returns
altitude in meters of measurement point
bme680.dewpoint()
For given temperature and relative humidity returns the dew point in Celsius as an integer multiplied with 100.
#### Syntaxbme680.dewpoint(H, T)
#### Parameters
- H relative humidity in percent multiplied by 1000.
- T temperate in Celsius multiplied by 100.
#### Returns
dew point in Celsius
bme680.qfe2qnh()
For given altitude converts the air pressure to sea level air pressure.
#### Syntaxbme680.qfe2qnh(P, altitude)
#### Parameters
- P measured pressure
- altitude altitude in meters of measurement point
#### Returns
sea level pressure
bme680.read()
Reads the sensor and returns the temperature, the air pressure, the air relative humidity and
#### Syntaxbme680.read([altitude])
#### Parameters
- (optional) altitude- altitude in meters of measurement point. If provided also the air pressure converted to sea level air pressure is returned.
#### Returns
- T temperature in Celsius as an integer multiplied with 100
- P air pressure in hectopascals multiplied by 100
- H relative humidity in percent multiplied by 1000
- G gas resistance
- QNH air pressure in hectopascals multiplied by 100 converted to sea level
Any of these variables is nil if the readout of given measure was not successful.
The measured values can be read only once. Following attempts to read values will return nil. A new startreadout() needs to be called first before next read().
bme680.startreadout()
Starts readout (turns the sensor into forced mode). After the readout the sensor turns to sleep mode.
#### Syntaxbme680.startreadout(delay, callback)
#### Parameters
- delay sets sensor to forced mode and calls the callback (if provided) after given number of milliseconds. For 0 the default delay is calculated by the formula provided by Bosch. Apparently for certain combinations of oversamplings setup the the delay returned by the formula is not sufficient and the readout is not ready (make sure you are not reading the previous measurement). For default parameters (2x, 16x, 1x) the calculated delay is 121 ms while in reality 150 ms are needed to get the result.
- callback if provided it will be invoked after given delay. The sensor reading should be finalized by then so.
#### Returnsnil
bme680.setup()
Initializes module. Initialization is mandatory before read values.
#### Syntax
bme680.setup([temp_oss, press_oss, humi_oss, heater_temp, heater_duration, IIR_filter, cold_start])
#### Parameters
- (optional) temp_oss - Controls oversampling of temperature data. Default oversampling is 2x.
- (optional) press_oss - Controls oversampling of pressure data. Default oversampling is 16x.
- (optional) humi_oss - Controls oversampling of humidity data. Default oversampling is 1x
- (optional) heater_temp -
- (optional) heater_duration -
- (optional) IIR_filter - Controls the time constant of the IIR filter. Default filter coefficient is 31.
- (optional) cold_start - If 0 then the bme680 chip is not initialised. Useful in a battery operated setup when the ESP deep sleeps and on wakeup needs to initialise the driver (the module) but not the chip itself. The chip was kept powered (sleeping too) and is holding the latest reading that should be fetched quickly before another reading starts (bme680.startreadout()). By default the chip is initialised.
|temp_oss, press_oss, humi_oss|Data oversampling|
|-----|-----------------|
|0|Skipped (output set to 0x80000)|
|1|oversampling Ć1|
|2|oversampling Ć2|
|3|oversampling Ć4|
|4|oversampling Ć8|
|5|oversampling Ć16|
|IIR_filter|Filter coefficient |
|-----|-----------------|
|0|Filter off|
|1|1|
|2|3|
|3|7|
|4|15|
|5|31|
|6|63|
|7|127|
#### Returnsnil if initialization has failed (no sensor connected?)
#### Example
alt=320 -- altitude of the measurement placesda, scl = 3, 4
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
bme680.setup()
-- delay calculated by formula provided by Bosch: 121 ms, minimum working (empirical): 150 ms
bme680.startreadout(150, function ()
T, P, H, G, QNH = bme680.read(alt)
if T then
local Tsgn = (T < 0 and -1 or 1); T = Tsgn*T
print(string.format("T=%s%d.%02d", Tsgn<0 and "-" or "", T/100, T%100))
print(string.format("QFE=%d.%03d", P/100, P%100))
print(string.format("QNH=%d.%03d", QNH/100, QNH%100))
print(string.format("humidity=%d.%03d%%", H/1000, H%1000))
print(string.format("gas resistance=%d", G))
D = bme680.dewpoint(H, T)
local Dsgn = (D < 0 and -1 or 1); D = Dsgn*D
print(string.format("dew_point=%s%d.%02d", Dsgn<0 and "-" or "", D/100, D%100))
end
end)
---
Modules/Bmp085
BMP085 Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-08-03 | Konrad Beckmann | Konrad Beckmann | bmp085.c|
This module provides access to the BMP085 temperature and pressure sensor. The module also works with BMP180.
bmp085.setup()
Initializes the module.
#### Syntaxbmp085.setup()
#### Parameters
None
#### Returnsnil
bmp085.temperature()
Samples the sensor and returns the temperature in celsius as an integer multiplied with 10.
#### Syntaxbmp085.temperature()
#### Returns
temperature multiplied with 10 (integer)
#### Example
local sda, scl = 1, 2
i2c.setup(0, sda, scl, i2c.SLOW)
bmp085.setup()
local t = bmp085.temperature()
print(string.format("Temperature: %s.%s degrees C", t / 10, t % 10))bmp085.pressure()
Samples the sensor and returns the pressure in pascal as an integer.
The optional oversampling_setting parameter determines for how long time the sensor samples data.
The default is 3 which is the longest sampling setting. Possible values are 0, 1, 2, 3.
See the data sheet for more information.
#### Syntaxbmp085.pressure(oversampling_setting)
#### Parametersoversampling_setting integer that can be 0, 1, 2 or 3
#### Returns
pressure in pascals (integer)
#### Example
local sda, scl = 1, 2
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
bmp085.setup()
local p = bmp085.pressure()
print(string.format("Pressure: %s.%s mbar", p / 100, p % 100))bmp085.pressure_raw()
Samples the sensor and returns the raw pressure in internal units. Might be useful if you need higher precision.
#### Syntaxbmp085.pressure_raw(oversampling_setting)
#### Parametersoversampling_setting integer that can be 0, 1, 2 or 3
#### Returns
raw pressure sampling value (integer)
---
Modules/Cjson
CJSON Module
This module has been replaced by sjson. It provides a superset of functionality. All references to cjson can be replaced by sjson.
---
Modules/Coap
CoAP Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-02-04 | Toby Jaffey <[email protected]>, Zeroday | Zeroday | coap.c |
The CoAP module provides a simple implementation according to CoAP protocol.
The basic endpoint server part is based on microcoap, and many other code reference libcoap.
This module implements both the client and the server side. GET/PUT/POST/DELETE is partially supported by the client. Server can register Lua functions and variables. No observe or discover supported yet.
!!! caution
This module is only in the very early stages and not complete yet.
Constants
Constants for various functions.
coap.CON, coap.NON represent the request types.
coap.TEXT_PLAIN, coap.LINKFORMAT, coap.XML, coap.OCTET_STREAM, coap.EXI, coap.JSON represent content types.
coap.Client()
Creates a CoAP client.
#### Syntaxcoap.Client()
#### Parameters
none
#### Returns
CoAP client
#### Example
cc = coap.Client()
-- assume there is a coap server at ip 192.168.100
cc:get(coap.CON, "coap://192.168.18.100:5683/.well-known/core")
-- GET is not complete, the result/payload only print out in console.
cc:post(coap.NON, "coap://192.168.18.100:5683/", "Hello")coap.Server()
Creates a CoAP server.
#### Syntaxcoap.Server()
#### Parameters
none
#### Returns
CoAP server
#### Example
-- use copper addon for firefox
cs=coap.Server()
cs:listen(5683)myvar=1
cs:var("myvar") -- get coap://192.168.18.103:5683/v1/v/myvar will return the value of myvar: 1
all='[1,2,3]'
cs:var("all", coap.JSON) -- sets content type to json
-- function should tack one string, return one string.
function myfun(payload)
print("myfun called")
respond = "hello"
return respond
end
cs:func("myfun") -- post coap://192.168.18.103:5683/v1/f/myfun will call myfun
CoAP Client
coap.client:get()
Issues a GET request to the server.
#### Syntaxcoap.client:get(type, uri[, payload])
#### Parameters
- type coap.CON, coap.NON, defaults to CON. If the type is CON and request fails, the library retries four more times before giving up.
- uri the URI such as "coap://192.168.18.103:5683/v1/v/myvar", only IP addresses are supported i.e. no hostname resoltion.
- payload optional, the payload will be put in the payload section of the request.
#### Returnsnil
coap.client:put()
Issues a PUT request to the server.
#### Syntaxcoap.client:put(type, uri[, payload])
#### Parameters
- type coap.CON, coap.NON, defaults to CON. If the type is CON and request fails, the library retries four more times before giving up.
- uri the URI such as "coap://192.168.18.103:5683/v1/v/myvar", only IP addresses are supported i.e. no hostname resoltion.
- payload optional, the payload will be put in the payload section of the request.
#### Returnsnil
coap.client:post()
Issues a POST request to the server.
#### Syntaxcoap.client:post(type, uri[, payload])
#### Parameters
- type coap.CON, coap.NON, defaults to CON. when type is CON, and request failed, the request will retry another 4 times before giving up.
- uri the uri such as coap://192.168.18.103:5683/v1/v/myvar, only IP is supported.
- payload optional, the payload will be put in the payload section of the request.
#### Returnsnil
coap.client:delete()
Issues a DELETE request to the server.
#### Syntaxcoap.client:delete(type, uri[, payload])
#### Parameters
- type coap.CON, coap.NON, defaults to CON. If the type is CON and request fails, the library retries four more times before giving up.
- uri the URI such as "coap://192.168.18.103:5683/v1/v/myvar", only IP addresses are supported i.e. no hostname resoltion.
- payload optional, the payload will be put in the payload section of the request.
#### Returnsnil
CoAP Server
coap.server:listen()
Starts the CoAP server on the given port.
#### Syntaxcoap.server:listen(port[, ip])
#### Parameters
- port server port (number)
- ip optional IP address
#### Returnsnil
coap.server:close()
Closes the CoAP server.
#### Syntaxcoap.server:close()
#### Parameters
none
#### Returnsnil
coap.server:var()
Registers a Lua variable as an endpoint in the server. the variable value then can be retrieved by a client via GET method, represented as an URI to the client. The endpoint path for variable is '/v1/v/'.
#### Syntaxcoap.server:var(name[, content_type])
#### Parameters
- name the Lua variable's name
- content_type optional, defaults to coap.TEXT_PLAIN, see Content Negotiation
#### Returnsnil
#### Example
-- use copper addon for firefox
cs=coap.Server()
cs:listen(5683)myvar=1
cs:var("myvar") -- get coap://192.168.18.103:5683/v1/v/myvar will return the value of myvar: 1
-- cs:var(myvar), WRONG, this api accept the name string of the varialbe. but not the variable itself.
all='[1,2,3]'
cs:var("all", coap.JSON) -- sets content type to json
coap.server:func()
Registers a Lua function as an endpoint in the server. The function then can be called by a client via POST method. represented as an URI to the client. The endpoint path for function is '/v1/f/'.
When the client issues a POST request to this URI, the payload will be passed to the function as parameter. The function's return value will be the payload in the message to the client.
The function registered SHOULD accept ONLY ONE string type parameter, and return ONE string value or return nothing.
#### Syntaxcoap.server:func(name[, content_type])
#### Parameters
- name the Lua function's name
- content_type optional, defaults to coap.TEXT_PLAIN, see Content Negotiation
#### Returnsnil
#### Example
-- use copper addon for firefox
cs=coap.Server()
cs:listen(5683)-- function should take only one string, return one string.
function myfun(payload)
print("myfun called")
respond = "hello"
return respond
end
cs:func("myfun") -- post coap://192.168.18.103:5683/v1/f/myfun will call myfun
-- cs:func(myfun), WRONG, this api accept the name string of the function. but not the function itself.
---
Modules/Color Utils
color utils Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2017-12-30 | Konrad Huebner | Konrad Huebner | color_utils.c|
This module provides basic color transformations useful for color LEDs.
color_utils.hsv2grb()
Convert HSV color to GRB color.
#### Syntaxcolor_utils.hsv2grb(hue, saturation, value)
#### Parameters
- hue is the hue value, between 0 and 360
- saturation is the saturation value, between 0 and 255
- value is the value value, between 0 and 255
#### Returnsgreen, red, blue as values between 0 and 255
color\_utils.hsv2grbw()
Convert HSV color to GRB color and explicitly return a white value. This can be useful for RGB+W LED strips. The white value is simply calculated as min(g, r, b) and then removed from the colors. This does NOT take into account if the white chip used later creates an appropriate color.
#### Syntaxcolor_utils.hsv2grbw(hue, saturation, value)
#### Parameters
- hue is the hue value, between 0 and 360
- saturation is the saturation value, between 0 and 255
- value is the value value, between 0 and 255
#### Returnsgreen, red, blue, white as values between 0 and 255
color\_utils.grb2hsv()
Convert GRB color to HSV color.
#### Syntaxcolor_utils.grb2hsv(green, red, blue)
#### Parameters
- green is the green value, between 0 and 255
- red is the red value, between 0 and 255
- blue is the blue value, between 0 and 255
#### Returnshue, saturation, value as values between 0 and 360, respective 0 and 255
color\_utils.colorWheel()
The color wheel function makes use of the HSV color space and calculates colors based on the color circle. The colors are created with full saturation and value. This function is a convenience function of the hsv2grb function and can be used to create rainbow colors.
#### Syntaxcolor_utils.colorWheel(angle)
#### Parameters
- angle is the angle on the color circle, between 0 and 359
#### Returnsgreen, red, blue as values between 0 and 255
---
Modules/Cron
Cron Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2016-12-18 | PhoeniX | PhoeniX | cron.c|
Cron-like scheduler module.
!!! important
This module needs RTC time to operate correctly. Do not forget to include the rtctime module and initialize it properly.
!!! important
The cron expression has to be in GMT/UTC!
cron.schedule()
Creates a new schedule entry.
#### Syntaxcron.schedule(mask, callback)
#### Parameters
- mask - crontab-like string mask for schedule
- callback - callback function(entry) that is executed at the scheduled time
#### Returnscron.entry sub module
#### Example
cron.schedule(" *", function(e)
print("Every minute")
end)cron.schedule("/5 *", function(e)
print("Every 5 minutes")
end)
cron.schedule("0 /2 ", function(e)
print("Every 2 hours")
end)
cron.reset()
Removes all scheduled entries.
#### Syntaxcron.reset()
#### Parameters
none
#### Returns
nil
cron.entry Module
cron.entry:handler()
Sets a new handler for entry.
#### Syntaxhandler(callback)
#### Parameters
- callback - callback function(entry) that is executed at the scheduled time
#### Returns
nil
#### Example
ent = cron.schedule(" *", function(e)
print("Every minute")
end)ent:handler(function(e)
print("New handler: Every minute")
end)
cron.entry:schedule()
Sets a new schedule mask.
#### Syntaxschedule(mask)
#### Parameters
- mask - crontab-like string mask for schedule
#### Returns
none
#### Example
ent = cron.schedule(" *", function(e)
print("Tick")
end)-- Every 5 minutes is really better!
ent:schedule("/5 *")
cron.entry:unschedule()
Disables schedule.
Disabled schedules may be enabled again by calling :schedule(mask).
#### Syntaxunschedule()
#### Parameters
none
#### Returns
nil
#### Example
ent = cron.schedule(" *", function(e)
print("Tick")
end)-- We don't need this anymore
ent:unschedule()
---
Modules/Crypto
crypto Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-06-02 | DiUS, Johny Mattsson | Johny Mattsson | crypto.c|
The crypto modules provides various functions for working with cryptographic algorithms.
The following encryption/decryption algorithms/modes are supported:
- "AES-ECB" for 128-bit AES in ECB mode (NOT recommended)
- "AES-CBC" for 128-bit AES in CBC mode
The following hash algorithms are supported:
- MD5
- SHA1
- SHA256, SHA384, SHA512 (unless disabled in app/include/user_config.h)
crypto.encrypt()
Encrypts Lua strings.
#### Syntaxcrypto.encrypt(algo, key, plain [, iv])
#### Parameters
- algo the name of a supported encryption algorithm to use
- key the encryption key as a string; for AES encryption this MUST be 16 bytes long
- plain the string to encrypt; it will be automatically zero-padded to a 16-byte boundary if necessary
- iv the initilization vector, if using AES-CBC; defaults to all-zero if not given
#### Returns
The encrypted data as a binary string. For AES this is always a multiple of 16 bytes in length.
#### Example
print(encoder.toHex(crypto.encrypt("AES-ECB", "1234567890abcdef", "Hi, I'm secret!")))#### See also
- crypto.decrypt()
crypto.decrypt()
Decrypts previously encrypted data.
#### Syntaxcrypto.decrypt(algo, key, cipher [, iv])
#### Parameters
- algo the name of a supported encryption algorithm to use
- key the encryption key as a string; for AES encryption this MUST be 16 bytes long
- cipher the cipher text to decrypt (as obtained from crypto.encrypt())
- iv the initialization vector, if using AES-CBC; defaults to all-zero if not given
#### Returns
The decrypted string.
Note that the decrypted string may contain extra zero-bytes of padding at the end. One way of stripping such padding is to use :match("(.-)%z*$") on the decrypted string. Additional care needs to be taken if working on binary data, in which case the real length likely needs to be encoded with the data, and at which point :sub(1, n) can be used to strip the padding.
#### Example
key = "1234567890abcdef"
cipher = crypto.encrypt("AES-ECB", key, "Hi, I'm secret!")
print(encoder.toHex(cipher))
print(crypto.decrypt("AES-ECB", key, cipher))#### See also
- crypto.encrypt()
crypto.fhash()
Compute a cryptographic hash of a a file.
#### Syntaxhash = crypto.fhash(algo, filename)
#### Parameters
- algo the hash algorithm to use, case insensitive string
- filename the path to the file to hash
#### Returns
A binary string containing the message digest. To obtain the textual version (ASCII hex characters), please use encoder.toHex().
#### Example
print(encoder.toHex(crypto.fhash("sha1","myfile.lua")))crypto.hash()
Compute a cryptographic hash of a Lua string.
#### Syntaxhash = crypto.hash(algo, str)
#### Parametersalgo the hash algorithm to use, case insensitive stringstr string to hash contents of
#### Returns
A binary string containing the message digest. To obtain the textual version (ASCII hex characters), please use encoder.toHex().
#### Example
print(encoder.toHex(crypto.hash("sha1","abc")))crypto.new_hash()
Create a digest/hash object that can have any number of strings added to it. Object has update and finalize functions.
#### Syntaxhashobj = crypto.new_hash(algo)
#### Parametersalgo the hash algorithm to use, case insensitive string
#### Returns
Userdata object with update and finalize functions available.
#### Example
hashobj = crypto.new_hash("SHA1")
hashobj:update("FirstString")
hashobj:update("SecondString")
digest = hashobj:finalize()
print(encoder.toHex(digest))crypto.hmac()
Compute a HMAC (Hashed Message Authentication Code) signature for a Lua string.
#### Syntaxsignature = crypto.hmac(algo, str, key)
#### Parameters
- algo hash algorithm to use, case insensitive string
- str data to calculate the hash for
- key key to use for signing, may be a binary string
#### Returns
A binary string containing the HMAC signature. Use encoder.toHex() to obtain the textual version.
#### Example
print(encoder.toHex(crypto.hmac("sha1","abc","mysecret")))crypto.new_hmac()
Create a hmac object that can have any number of strings added to it. Object has update and finalize functions.
#### Syntaxhmacobj = crypto.new_hmac(algo, key)
#### Parameters
- algo the hash algorithm to use, case insensitive string
- key the key to use (may be a binary string)
#### Returns
Userdata object with update and finalize functions available.
#### Example
hmacobj = crypto.new_hmac("SHA1", "s3kr3t")
hmacobj:update("FirstString")
hmacobj:update("SecondString")
digest = hmacobj:finalize()
print(encoder.toHex(digest))crypto.mask()
Applies an XOR mask to a Lua string. Note that this is not a proper cryptographic mechanism, but some protocols may use it nevertheless.
#### Syntaxcrypto.mask(message, mask)
#### Parameters
- message message to mask
- mask the mask to apply, repeated if shorter than the message
#### Returns
The masked message, as a binary string. Use encoder.toHex() to get a textual representation of it.
#### Example
print(encoder.toHex(crypto.mask("some message to obscure","X0Y7")))---
Modules/Dcc
DCC module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2019-12-28 | vsky279 | vsky279 | dcc.c|
The dcc module implements decoder of the National Model Railroad Association (NMRA) Digital Command Control (DCC) decoder - see DCC wiki for details.
The hardware needed to decode the DCC signal can be built based on different DCC decoders implementation for Arduino, for inspiration see https://mrrwa.org/dcc-decoder-interface/. Basically the signal from the DCC bus is connected via an optocoupler to any GPIO pin. The DCC bus can be also used to power the ESP.
The module is based on the project NmraDcc https://github.com/mrrwa/NmraDcc by Alex Shepherd (@kiwi64ajs). The module is based on latest commit from Oct 2020, commit 7e3b3e346991d74926e6c4f6fb46e27156b08578.
dcc.setup()
Initializes the dcc module and links callback functions.
#### Syntaxdcc.setup(Pin, [AckPin, ] DCC_command, ManufacturerId, VersionId, Flags, OpsModeAddressBaseCV [, CV_table] [, CV_callback])
#### Parameters
- Pin the GPIO pin number connected to the DCC detector (must be interrupt capable pin).
- AckPin the (optional) GPIO pin number connected to the ACK mechanism. Will be set HIGH to signal an ACK.
- DCC_command(cmd, params) calllback function that is called when a DCC command is decoded. cmd parameters is one of the following values. params contains a collection of parameters specific to given command.
- dcc.DCC_RESET no additional parameters, params is nil.
- dcc.DCC_IDLE no additional parameters, params is nil.
- dcc.DCC_SPEED parameters collection members are Addr, AddrType, Speed, Dir, SpeedSteps.
- dcc.DCC_SPEED_RAW parameters collection members are Addr, AddrType, Raw.
- dcc.DCC_FUNC parameters collection members are Addr, AddrType, FuncGrp, FuncState.
- dcc.DCC_TURNOUT parameters collection members are BoardAddr, OutputPair, Direction, OutputPower or Addr, Direction, OutputPower.
- dcc.DCC_ACCESSORY parameters collection has one member BoardAddr or Addr or State.
- dcc.DCC_RAW parameters collection member are Size, PreambleBits, Data1 to Data6.
- dcc.DCC_SERVICEMODE parameters collection has one member InServiceMode.
- ManufacturerId Manufacturer ID returned in CV 8. Commonly dcc.MAN_ID_DIY.
- VersionId Version ID returned in CV 7.
- Flags one of or combination (OR operator) of
- dcc.FLAGS_MY_ADDRESS_ONLYOnly process packets with My Address.
- dcc.FLAGS_DCC_ACCESSORY_DECODER Decoder is an accessory decode.
- dcc.FLAGS_OUTPUT_ADDRESS_MODE This flag applies to accessory decoders only. Accessory decoders normally have 4 paired outputs and a single address refers to all 4 outputs. Setting this flag causes each address to refer to a single output.
- dcc.FLAGS_AUTO_FACTORY_DEFAULT Call DCC command callback with dcc.CV_RESET command if CV 7 & 8 == 255.
- OpsModeAddressBaseCV Ops Mode base address. Set it to 0?
- CV_table The CV values will be directly accessed from this table. metamethods will be invoked if needed. Any errors thrown will cause the CV to be considered invalid. Using this option will prevent CV_VALID, CV_READ, CV_WRITE and CV_ACK_COMPLETE from happening.
- CV_callback(operation, param) callback function that is called when any manipulation with CV (Configuarion Variable) is requested.
- dcc.CV_VALID to determine if a given CV is valid and (possibly) writable. This callback must determine if a CV is readable or writable and return the appropriate value(0/1/true/false). The param collection has members CV and Writable.
- dcc.CV_READ to read a CV. This callback must return the value of the CV. The param collection has one member CV determing the CV number to be read.
- dcc.CV_WRITE to write a value to a CV. This callback must write the Value to the CV and return the value of the CV. The param collection has members CV and Value. Ideally, the final value should be returned -- this may differ from the requested value.
- dcc.CV_RESET Called when CVs must be reset to their factory defaults.
- dcc.CV_ACK_COMPLETE Called when an ACK pulse has finished being sent. Only invoked if AckPin is specified.
#### Returnsnil
#### Examplebit module is used in the example though it is not needed for the dcc module functionality.
/ Detailed source-code truncated for AI context efficiency. /dcc.close()
Stops the dcc module.
#### Syntaxdcc.close()
#### Parametersnil
#### Returnsnil
---
Modules/Dht
DHT Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-06-17 | RobTillaart | Vowstar | dhtlib|
Constants
Constants for various functions.
dht.OK, dht.ERROR_CHECKSUM, dht.ERROR_TIMEOUT represent the potential values for the DHT read status
dht.read()
Reads all kinds of DHT sensors, including DHT11, 21, 22, 33, 44 humidity temperature combo sensor.
Returns correct readout except for DHT12 and negative temperatures by DHT11. Use
dht.read12() and dht.read11() instead. It is to use model specific read function anyway.#### Syntaxdht.read(pin)
#### Parameterspin pin number of DHT sensor (can't be 0), type is number
#### Returns
- status as defined in Constants
- temp temperature (see note below)
- humi humidity (see note below)
- temp_dec temperature decimal
- humi_dec humidity decimal
!!! note
If using float firmware then temp and humi are floating point numbers. On an integer firmware, the final values have to be concatenated from temp and temp_dec / humi and hum_dec.
#### Example
pin = 5
status, temp, humi, temp_dec, humi_dec = dht.read(pin)
if status == dht.OK then
-- Integer firmware using this example
print(string.format("DHT Temperature:%d.%03d;Humidity:%d.%03d\r\n",
math.floor(temp),
temp_dec,
math.floor(humi),
humi_dec
)) -- Float firmware using this example
print("DHT Temperature:"..temp..";".."Humidity:"..humi)
elseif status == dht.ERROR_CHECKSUM then
print( "DHT Checksum error." )
elseif status == dht.ERROR_TIMEOUT then
print( "DHT timed out." )
end
dht.read11()
Read DHT11 humidity temperature combo sensor.
#### Syntaxdht.read11(pin)
#### Parameterspin pin number of DHT11 sensor (can't be 0), type is number
#### Returns
- status as defined in Constants
- temp temperature (see note below)
- humi humidity (see note below)
- temp_dec temperature decimal
- humi_dec humidity decimal
!!! note
If using float firmware then temp and humi are floating point numbers. On an integer firmware, the final values have to be concatenated from temp and temp_dec / humi and hum_dec.
#### See also
dht.read()
dht.read12()
Read DHT12 humidity temperature combo sensor.
#### Syntaxdht.read12(pin)
#### Parameterspin pin number of DHT12 sensor (can't be 0), type is number
#### Returns
- status as defined in Constants
- temp temperature (see note below)
- humi humidity (see note below)
- temp_dec temperature decimal
- humi_dec humidity decimal
!!! note
If using float firmware then temp and humi are floating point numbers. On an integer firmware, the final values have to be concatenated from temp and temp_dec / humi and hum_dec.
#### See also
dht.read()
dht.readxx()
Read all kinds of DHT sensors, except DHT11 and DHT12. Differs from
dht.read() only by waiting only sufficient 1 ms for sensor wake-up while dht.read() waits universal 18 ms.####Syntaxdht.readxx(pin)
#### Parameterspin pin number of DHT sensor (can't be 0), type is number
#### Returns
- status as defined in Constants
- temp temperature (see note below)
- humi humidity (see note below)
- temp_dec temperature decimal
- humi_dec humidity decimal
!!! note
If using float firmware then temp and humi are floating point numbers. On an integer firmware, the final values have to be concatenated from temp and temp_dec / humi and hum_dec.
#### See also
dht.read()
---
Modules/Encoder
encoder Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2016-02-26 | Terry Ellison | Terry Ellison | encoder.c|
The encoder modules provides various functions for encoding and decoding byte data.
encoder.toBase64()
Provides a Base64 representation of a (binary) Lua string.
#### Syntaxb64 = encoder.toBase64(binary)
#### Parametersbinary input string to Base64 encode
#### Return
A Base64 encoded string.
#### Example
print(encoder.toBase64(crypto.hash("sha1","abc")))encoder.fromBase64()
Decodes a Base64 representation of a (binary) Lua string back into the original string. An error is
thrown if the string is not a valid base64 encoding.
#### Syntaxbinary_string = encoder.fromBase64(b64)
#### Parametersb64 Base64 encoded input string
#### Return
The decoded Lua (binary) string.
#### Example
print(encoder.fromBase64(encoder.toBase64("hello world")))encoder.toHex()
Provides an ASCII hex representation of a (binary) Lua string. Each byte in the input string is
represented as two hex characters in the output.
#### Syntaxhexstr = encoder.toHex(binary)
#### Parametersbinary input string to get hex representation for
#### Returns
An ASCII hex string.
#### Example
print(encoder.toHex(crypto.hash("sha1","abc")))encoder.fromHex()
Returns the Lua binary string decode of a ASCII hex string. Each byte in the output string is
represented as two hex characters in the input. An error is thrown if the string is not a
valid base64 encoding.
#### Syntaxbinary = encoder.fromHex(hexstr)
#### Parametershexstr An ASCII hex string.
#### Returns
Decoded string of hex representation.
#### Example
print(encoder.fromHex("6a6a6a"))---
Modules/Enduser Setup
enduser setup Module aka Captive Portal aka WiFi Manager
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2015-09-02 | Robert Foss | Robert Foss | enduser_setup.c|
This module provides a simple way of configuring ESP8266 chips without using a
serial interface or pre-programming WiFi credentials onto the chip.
After running enduser_setup.start(), a wireless
network named "NodeMCU_XXXXXX" will start. This prefix can be overridden
in user_config.h by defining ENDUSER_SETUP_AP_SSID or by supplying the whole SSID to theenduser_setup.start method. Connect to that SSID and captive portal detection on the client
should automatically open the configuration dialog. If not, then
navigate to the root of any website or to 192.168.4.1. http://example.com/ will work, but do not use .local domains because it
will fail on iOS. A web page similar to the one depicted below will load,
allowing the end user to provide their Wi-Fi credentials.
After an IP address has been successfully obtained, then this module will stop
as if enduser_setup.stop() had been called. There is a
10-second delay before teardown to allow connected clients to obtain a last
status message while the SoftAP is still active.
Alternative HTML can be served by placing a file called enduser_setup.html on
the filesystem. Everything needed by the web page must be included in this one
file. This file will be kept in RAM, so keep it as small as possible. The file
can be gzip'd ahead of time to reduce the size (i.e., using gzip -n orzopfli), and when served, the End User Setup module will add the appropriateContent-Encoding header to the response.
*Note: If gzipped, the file can also be named enduser_setup.html.gz for
semantic purposes. GZIP encoding is determined by the file's contents, not the
filename.*
Additional configuration parameters
You can also add some additional inputs in the enduser_setup.html (as long as
you keep those needed for the WiFi setup). The additional data will be written
in a eus_params.lua file in the root filesystem of the ESP8266, which you can
then load in your own code. In this case, the data will be saved as a set of
variables with the name being the input name, and the value being a string
representing what you put in the form.
For instance, if your HTML contains two additional inputs:
<input name=timeout_delay type=text placeholder="Delay in seconds" />
<input name=device_name type=text placeholder="Unique device name" />Then the eus_params.lua file will contain the following:
-- those wifi_* are the base parameters that are saved anyway
local p = {}
p.wifi_ssid="ssid"
p.wifi_password="password"
-- your own parameters:
p.timeout_delay="xxx"
p.device_name="yyy"
return pHow to use the eus_params.lua file
Simply include the file by using the dofile function:
p = dofile('eus_params.lua')
-- now use the parameters in the Lua table
print("Wifi device_name: " .. p.device_name)HTTP endpoints:
|Path|Method|Description|
|----|------|-----------|
|/|GET|Returns HTML for the web page. Will return the contents of enduser_setup.html if it exists on the filesystem, otherwise will return a page embedded into the firmware image.|
|/aplist|GET|Forces the ESP8266 to perform a site survey across all channels, reporting access points that it can find. Return payload is a JSON array: [{"ssid":"foobar","rssi":-36,"chan":3}]|
|/status|GET|Returns plaintext status description, used by the web page|
|/status.json|GET|Returns a JSON payload containing the ESP8266's chip id in hexadecimal format and the status code: 0=Idle, 1=Connecting, 2=Wrong Password, 3=Network not Found, 4=Failed, 5=Success|
|/setwifi|POST|HTML form post for setting the WiFi credentials. Expects HTTP content type application/x-www-form-urlencoded. Supports sending and storing additinal configuration parameters (as input fields). Returns the same payload as /status.json instead of redirecting to /. See also: /update.|
|/update|GET|Data submission target. Example: http://example.com/update?wifi_ssid=foobar&wifi_password=CorrectHorseBatteryStaple. Will redirect to / when complete. Note that will NOT update the eus_params.lua file i.e. it does NOT support sending arbitrary parameters. See also: /setwifi. |
Module functions are described below.
enduser_setup.manual()
Controls whether manual AP configuration is used.
By default the enduser_setup module automatically configures an open access
point when starting, and stops it when the device has been successfully joined
to a WiFi network. If manual mode has been enabled, neither of this is done.
The device must be manually configured for wifi.SOFTAP mode prior to calling enduser_setup.start(). Additionally, the portal is not stopped after the
device has successfully joined to a WiFi network.
#### Syntaxenduser_setup.manual([on_off])
#### Parameters
- on_off a boolean value indicating whether to use manual mode; if not
given, the function only returns the current setting.
#### Returns
The current setting, true if manual mode is enabled, false if it is not.
#### Example
wifi.setmode(wifi.STATIONAP)
wifi.ap.config({ssid="MyPersonalSSID", auth=wifi.OPEN})
enduser_setup.manual(true)
enduser_setup.start(
function()
print("Connected to WiFi as:" .. wifi.sta.getip())
end,
function(err, str)
print("enduser_setup: Err #" .. err .. ": " .. str)
end
)enduser_setup.start()
Starts the captive portal.
Note: Calling start() while EUS is already running is an error, and will result in stop() to be invoked to shut down EUS.
#### Syntaxenduser_setup.start([AP_SSID,] [onConnected()], [onError(err_num, string)], [onDebug(string)])
#### Parameters
- AP_SSID the (optional) SSID to use for the AP. This defaults to NodeMCU_<device id>.
- onConnected() callback will be fired when an IP-address has been obtained, just before the enduser_setup module will terminate itself
- onError() callback will be fired if an error is encountered. err_num is a number describing the error, and string contains a description of the error.
- onDebug() callback is disabled by default (controlled by #define ENDUSER_SETUP_DEBUG_ENABLE in enduser_setup.c). It is intended to be used to find internal issues in the module. string contains a description of what is going on.
#### Returnsnil
#### Example
enduser_setup.start(
function()
print("Connected to WiFi as:" .. wifi.sta.getip())
end,
function(err, str)
print("enduser_setup: Err #" .. err .. ": " .. str)
end,
print -- Lua print function can serve as the debug callback
)enduser_setup.stop()
Stops the captive portal.
#### Syntaxenduser_setup.stop()
#### Parameters
none
#### Returnsnil
---
Modules/File
file Module
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| 2014-12-22 | Zeroday | Zeroday | file.c|
The file module provides access to the file system and its individual files.
The file system is a flat file system, with no notion of subdirectories/folders.
Besides the SPIFFS file system on internal flash, this module can also access FAT partitions on an external SD card if FatFS is enabled.
-- open file in flash:
if file.open("init.lua") then
print(file.read())
file.close()
end-- or with full pathspec
file.open("/FLASH/init.lua")
-- open file on SD card
if file.open("/SD0/somefile.txt") then
print(file.read())
file.close()
end
file.chdir()
Change current directory (and drive). This will be used when no drive/directory is prepended to filenames.
Current directory defaults to the root of internal SPIFFS (/FLASH) after system start.
!!! note
Function is only available when FatFS support is compiled into the firmware.
#### Syntaxfile.chdir(dir)
#### Parametersdir directory name - /FLASH, /SD0, /SD1, etc.
#### Returnstrue on success, false otherwise
file.exists()
Determines whether the specified file exists.
#### Syntaxfile.exists(filename)
#### Parameters
- filename file to check
#### Returns
true if the file exists (even if 0 bytes in size), and false if it does not exist
#### Example
files = file.list()
if files["device.config"] then
print("Config file exists")
endif file.exists("device.config") then
print("Config file exists")
end
#### See also
file.list()file.format()
Format the file system. Completely erases any existing file system and writes a new one. Depending on the size of the flash chip in the ESP, this may take several seconds.
!!! note
Function is not supported for SD cards.
#### Syntaxfile.format()
#### Parameters
none
#### Returnsnil
#### See alsofile.remove()
file.fscfg ()
Returns the flash address and physical size of the file system area, in bytes.
!!! note
Function is not supported for SD cards.
#### Syntaxfile.fscfg()
#### Parameters
none
#### Returns
- flash address (number)
- size (number)
#### Example
print(string.format("0x%x", file.fscfg()))file.fsinfo()
Return size information for the file system. The unit is Byte for SPIFFS and kByte for FatFS.
#### Syntaxfile.fsinfo()
#### Parameters
none
#### Returns
- remaining (number)
- used (number)
- total (number)
#### Example
-- get file system info
remaining, used, total=file.fsinfo()
print("\nFile system info:\nTotal : "..total.." (k)Bytes\nUsed : "..used.." (k)Bytes\nRemain: "..remaining.." (k)Bytes\n")file.getcontents()
Open and read the contents of a file.
#### Syntaxfile.getcontents(filename)
#### Parameters
- filename file to be opened and read
#### Returns
file contents if the file exists. nil if the file does not exist.
#### Example (basic model)
print(file.getcontents('welcome.txt'))#### See also
-
file.putcontents()file.list()
Lists all files in the file system.
#### Syntaxfile.list([pattern])
#### Parameters
- pattern only files matching the Lua pattern will be returned
#### Returns
a Lua table which contains all {file name: file size} pairs, if no pattern
given. If a pattern is given, only those file names matching the pattern
(interpreted as a traditional Lua pattern,
not, say, a UNIX shell glob) will be included in the resulting table.file.list will throw any errors encountered during pattern matching.
#### Example
l = file.list();
for k,v in pairs(l) do
print("name:"..k..", size:"..v)
endfile.mount()
Mounts a FatFs volume on SD card.
!!! note
Function is only available when FatFS support is compiled into the firmware and it is not supported for internal flash.
#### Syntaxfile.mount(ldrv[, pin])
#### Parameters
- ldrv name of the logical drive, /SD0, /SD1, etc.
- pin 1~12, IO index for SS/CS, defaults to 8 if omitted.
#### Returns
Volume object
#### Example
vol = file.mount("/SD0")
vol:umount()file.on()
Registers callback functions.
Trigger events are:
- rtc deliver current date & time to the file system. Function is expected to return a table containing the fields year, mon, day, hour, min, sec of current date and time. Not supported for internal flash.
#### Syntaxfile.on(event[, function()])
#### Parameters
- event string
- function() callback function. Unregisters the callback if function() is omitted or nil.
#### Returnsnil
#### Example
sntp.sync(server_ip,
function()
print("sntp time sync ok")
file.on("rtc",
function()
return rtctime.epoch2cal(rtctime.get())
end)
end)#### See alsortctime.epoch2cal()
file.open()
Opens a file for access, potentially creating it (for write modes).
When done with the file, it must be closed using file.close().
#### Syntaxfile.open(filename, mode)
#### Parameters
- filename file to be opened
- mode:
- "r": read mode (the default)
- "w": write mode
- "a": append mode
- "r+": update mode, all previous data is preserved
- "w+": update mode, all previous data is erased
- "a+": append update mode, previous data is preserved, writing is only allowed at the end of file
#### Returns
file object if file opened ok. nil if file not opened, or not exists (read modes).
#### Example (basic model)
-- open 'init.lua', print the first line.
if file.open("init.lua", "r") then
print(file.readline())
file.close()
end#### Example (object model)
-- open 'init.lua', print the first line.
fd = file.open("init.lua", "r")
if fd then
print(fd:readline())
fd:close(); fd = nil
end#### See also
- file.close()
- file.readline()
file.remove()
Remove a file from the file system. The file must not be currently open.
###Syntaxfile.remove(filename)
#### Parametersfilename file to remove
#### Returnsnil
#### Example
-- remove "foo.lua" from file system.
file.remove("foo.lua")#### See also
file.open()file.putcontents()
Open and write the contents of a file.
#### Syntaxfile.putcontents(filename, contents)
#### Parameters
- filename file to be created
- contents to be written to the file
#### Returnstrue if the write is ok, nil on error
#### Example (basic model)
file.putcontents('welcome.txt', [[
Hello to new user
-----------------
]])#### See also
-
file.getcontents()file.rename()
Renames a file. If a file is currently open, it will be closed first.
#### Syntaxfile.rename(oldname, newname)
#### Parameters
- oldname old file name
- newname new file name
#### Returnstrue on success, false on error.
#### Example
-- rename file 'temp.lua' to 'init.lua'.
file.rename("temp.lua","init.lua")file.stat()
Get attribtues of a file or directory in a table. Elements of the table are:
- size file size in bytes
- name file name
- time table with time stamp information. Default is 1970-01-01 00:00:00 in case time stamps are not supported (on SPIFFS).
- year
- mon
- day
- hour
- min
- sec
- is_dir flag true if item is a directory, otherwise false
- is_rdonly flag true if item is read-only, otherwise false
- is_hidden flag true if item is hidden, otherwise false
- is_sys flag true if item is system, otherwise false
- is_arch flag true if item is archive, otherwise false
#### Syntaxfile.stat(filename)
#### Parametersfilename file name
#### Returns
table containing file attributes
#### Example
s = file.stat("/SD0/myfile")
print("name: " .. s.name)
print("size: " .. s.size)t = s.time
print(string.format("%02d:%02d:%02d", t.hour, t.min, t.sec))
print(string.format("%04d-%02d-%02d", t.year, t.mon, t.day))
if s.is_dir then print("is directory") else print("is file") end
if s.is_rdonly then print("is read-only") else print("is writable") end
if s.is_hidden then print("is hidden") else print("is not hidden") end
if s.is_sys then print("is system") else print("is not system") end
if s.is_arch then print("is archive") else print("is not archive") end
s = nil
t = nil
File access functions
The file module provides several functions to access the content of a file after it has been opened with file.open(). They can be used as part of a basic model or an object model:
Basic model
In the basic model there is max one file opened at a time. The file access functions operate on this file per default. If another file is opened, the previous default file needs to be closed beforehand.
-- open 'init.lua', print the first line.
if file.open("init.lua", "r") then
print(file.readline())
file.close()
endObject model
Files are represented by file objects which are created by
file.open(). File access functions are available as methods of this object, and multiple file objects can coexist.src = file.open("init.lua", "r")
if src then
dest = file.open("copy.lua", "w")
if dest then
local line
repeat
line = src:read()
if line then
dest:write(line)
end
until line == nil
dest:close(); dest = nil
end
src:close(); dest = nil
end!!! Attention
It is recommended to use only one single model within the application. Concurrent use of both models can yield unpredictable behavior: Closing the default file from basic model will also close the corresponding file object. Closing a file from object model will also close the default file if they are the same file.
!!! Note
The maximum number of open files on SPIFFS is determined at compile time by SPIFFS_MAX_OPEN_FILES in user_config.h.
file.close(), file.obj:close()
Closes the open file, if any.
#### Syntaxfile.close()
fd:close()
#### Parameters
none
#### Returnsnil
#### See alsofile.open()
file.flush(), file.obj:flush()
Flushes any pending writes to the file system, ensuring no data is lost on a restart. Closing the open file using file.close() / fd:close() performs an implicit flush as well.
#### Syntaxfile.flush()
fd:flush()
#### Parameters
none
#### Returnsnil
#### Example (basic model)
-- open 'init.lua' in 'a+' mode
if file.open("init.lua", "a+") then
-- write 'foo bar' to the end of the file
file.write('foo bar')
file.flush()
-- write 'baz' too
file.write('baz')
file.close()
end#### See alsofile.close() / file.obj:close()
file.read(), file.obj:read()
Read content from the open file.
!!! note
The function temporarily allocates 2 * (number of requested bytes) on the heap for buffering and processing the read data. Default chunk size (FILE_READ_CHUNK) is 1024 bytes and is regarded to be safe. Pushing this by 4x or more can cause heap overflows depending on the application. Consider this when selecting a value for parameter n_or_char.
#### Syntaxfile.read([n_or_char])
fd:read([n_or_char])
#### Parameters
- n_or_char:
- if nothing passed in, then read up to FILE_READ_CHUNK bytes or the entire file (whichever is smaller).
- if passed a number n, then read up to n bytes or the entire file (whichever is smaller).
- if passed a string containing the single character char, then read until char appears next in the file, FILE_READ_CHUNK bytes have been read, or EOF is reached.
#### Returns
File content as a string, or nil when EOF
#### Example (basic model)
-- print the first line of 'init.lua'
if file.open("init.lua", "r") then
print(file.read('\n'))
file.close()
end#### Example (object model)
-- print the first 5 bytes of 'init.lua'
fd = file.open("init.lua", "r")
if fd then
print(fd:read(5))
fd:close(); fd = nil
end#### See also
- file.open()
- file.readline() / file.obj:readline()
file.readline(), file.obj:readline()
Read the next line from the open file. Lines are defined as zero or more bytes ending with a EOL ('\n') byte. If the next line is longer than 1024, this function only returns the first 1024 bytes.
#### Syntaxfile.readline()
fd:readline()
#### Parameters
none
#### Returns
File content in string, line by line, including EOL('\n'). Return nil when EOF.
#### Example (basic model)
-- print the first line of 'init.lua'
if file.open("init.lua", "r") then
print(file.readline())
file.close()
end#### See also
- file.open()
- file.close() / file.obj:close()
- file.read() / file.obj:read()
file.seek(), file.obj:seek()
Sets and gets the file position, measured from the beginning of the file, to the position given by offset plus a base specified by the string whence.
#### Syntaxfile.seek([whence [, offset]])
fd:seek([whence [, offset]])
#### Parameters
- whence
- "set": base is position 0 (beginning of the file)
- "cur": base is current position (default value)
- "end": base is end of file
- offset default 0
If no parameters are given, the function simply returns the current file offset.
#### Returns
the resulting file position, or nil on error
#### Example (basic model)
if file.open("init.lua", "r") then
-- skip the first 5 bytes of the file
file.seek("set", 5)
print(file.readline())
file.close()
end#### See also
file.open()file.write(), file.obj:write()
Write a string to the open file.
#### Syntaxfile.write(string)
fd:write(string)
#### Parametersstring content to be write to file
#### Returnstrue if the write is ok, nil on error
#### Example (basic model)
-- open 'init.lua' in 'a+' mode
if file.open("init.lua", "a+") then
-- write 'foo bar' to the end of the file
file.write('foo bar')
file.close()
end#### Example (object model)
-- open 'init.lua' in 'a+' mode
fd = file.open("init.lua", "a+")
if fd then
-- write 'foo bar' to the end of the file
fd:write('foo bar')
fd:close()
end#### See also
- file.open()
- file.writeline() / file.obj:writeline()
file.writeline(), file.obj:writeline()
Write a string to the open file and append '\n' at the end.
#### Syntaxfile.writeline(string)
fd:writeline(string)
#### Parametersstring content to be write to file
#### Returnstrue if write ok, nil on error
#### Example (basic model)
-- open 'init.lua' in 'a+' mode
if file.open("init.lua", "a+") then
-- write 'foo bar' to the end of the file
file.writeline('foo bar')
file.close()
end#### See also
- file.open()
- file.readline() / file.obj:readline()
---