Merge branch 'newdocs' into dev

This commit is contained in:
Marcel Stör 2016-01-17 14:23:13 +01:00
commit 82b19c4c37
50 changed files with 6441 additions and 170 deletions

168
README.md
View File

@ -2,6 +2,7 @@
[![Join the chat at https://gitter.im/nodemcu/nodemcu-firmware](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/nodemcu/nodemcu-firmware?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/nodemcu/nodemcu-firmware.svg)](https://travis-ci.org/nodemcu/nodemcu-firmware)
[![Documentation Status](https://readthedocs.org/projects/nodemcu/badge/?version=newdocs)](http://nodemcu.readthedocs.org/en/newdocs/?badge=newdocs)
###A lua based firmware for wifi-soc esp8266
- Build on [ESP8266 NONOS SDK 1.5.1](http://bbs.espressif.com/viewtopic.php?f=46&p=5315)
@ -411,173 +412,6 @@ Victor Brutskiy's [ESPlorer](https://github.com/4refr0nt/ESPlorer) is written in
package.loaded["ds18b20"]=nil
```
####Operate a display with u8glib
u8glib is a graphics library with support for many different displays. The nodemcu firmware supports a subset of these.
Both I2C and SPI:
* sh1106_128x64
* ssd1306 - 128x64 and 64x48 variants
* ssd1309_128x64
* ssd1327_96x96_gr
* uc1611 - dogm240 and dogxl240 variants
SPI only:
* ld7032_60x32
* pcd8544_84x48
* pcf8812_96x65
* ssd1322_nhd31oled - bw and gr variants
* ssd1325_nhd27oled - bw and gr variants
* ssd1351_128x128 - gh and hicolor variants
* st7565_64128n - variants 64128n, dogm128/132, lm6059/lm6063, c12832/c12864
* uc1601_c128032
* uc1608 - 240x128 and 240x64 variants
* uc1610_dogxl160 - bw and gr variants
* uc1611 - dogm240 and dogxl240 variants
* uc1701 - dogs102 and mini12864 variants
U8glib v1.18.1
#####I2C connection
Hook up SDA and SCL to any free GPIOs. Eg. [u8g_graphics_test.lua](lua_examples/u8glib/u8g_graphics_test.lua) expects SDA=5 (GPIO14) and SCL=6 (GPIO12). They are used to set up nodemcu's I2C driver before accessing the display:
```lua
sda = 5
scl = 6
i2c.setup(0, sda, scl, i2c.SLOW)
```
#####SPI connection
The HSPI module is used ([more information](http://d.av.id.au/blog/esp8266-hardware-spi-hspi-general-info-and-pinout/)), so certain pins are fixed:
* HSPI CLK = GPIO14
* HSPI MOSI = GPIO13
* HSPI MISO = GPIO12 (not used)
All other pins can be assigned to any available GPIO:
* CS
* D/C
* RES (optional for some displays)
Also refer to the initialization sequence eg in [u8g_graphics_test.lua](lua_examples/u8glib/u8g_graphics_test.lua):
```lua
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
```
#####Library usage
The Lua bindings for this library closely follow u8glib's object oriented C++ API. Based on the u8g class, you create an object for your display type.
SSD1306 via I2C:
```lua
sla = 0x3c
disp = u8g.ssd1306_128x64_i2c(sla)
```
SSD1306 via SPI:
```lua
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
```
This object provides all of u8glib's methods to control the display.
Again, refer to [u8g_graphics_test.lua](lua_examples/u8glib/u8g_graphics_test.lua) to get an impression how this is achieved with Lua code. Visit the [u8glib homepage](https://github.com/olikraus/u8glib) for technical details.
#####Displays
I2C and HW SPI based displays with support in u8glib can be enabled. To get access to the respective constructors, add the desired entries to the I2C or SPI display tables in [app/include/u8g_config.h](app/include/u8g_config.h):
```c
#define U8G_DISPLAY_TABLE_I2C \
U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_i2c) \
#define U8G_DISPLAY_TABLE_SPI \
U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_hw_spi) \
U8G_DISPLAY_TABLE_ENTRY(pcd8544_84x48_hw_spi) \
U8G_DISPLAY_TABLE_ENTRY(pcf8812_96x65_hw_spi) \
```
An exhaustive list of available displays can be found in the [u8g module wiki entry](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_en#u8g-module).
#####Fonts
u8glib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in [app/include/u8g_config.h](app/include/u8g_config.h) and recompile. Simply add the desired fonts to the font table:
```c
#define U8G_FONT_TABLE \
U8G_FONT_TABLE_ENTRY(font_6x10) \
U8G_FONT_TABLE_ENTRY(font_chikita)
```
They'll be available as `u8g.<font_name>` in Lua.
#####Bitmaps
Bitmaps and XBMs are supplied as strings to `drawBitmap()` and `drawXBM()`. This off-loads all data handling from the u8g module to generic methods for binary files. See [u8g_bitmaps.lua](lua_examples/u8glib/u8g_bitmaps.lua).
In contrast to the source code based inclusion of XBMs into u8glib, it's required to provide precompiled binary files. This can be performed online with [Online-Utility's Image Converter](http://www.online-utility.org/image_converter.jsp): Convert from XBM to MONO format and upload the binary result with [nodemcu-uploader.py](https://github.com/kmpm/nodemcu-uploader).
#####Unimplemented functions
- [ ] Cursor handling
- [ ] disableCursor()
- [ ] enableCursor()
- [ ] setCursorColor()
- [ ] setCursorFont()
- [ ] setCursorPos()
- [ ] setCursorStyle()
- [ ] General functions
- [ ] setContrast()
- [ ] setPrintPos()
- [ ] setHardwareBackup()
- [ ] setRGB()
- [ ] setDefaultMidColor()
####Operate a display with ucglib
Ucglib is a graphics library with support for color TFT displays.
Ucglib v1.3.3
#####SPI connection
The HSPI module is used ([more information](http://d.av.id.au/blog/esp8266-hardware-spi-hspi-general-info-and-pinout/)), so certain pins are fixed:
* HSPI CLK = GPIO14
* HSPI MOSI = GPIO13
* HSPI MISO = GPIO12 (not used)
All other pins can be assigned to any available GPIO:
* CS
* D/C
* RES (optional for some displays)
Also refer to the initialization sequence eg in [GraphicsTest.lua](lua_examples/ucglib/GraphicsRest.lua):
```lua
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
```
#####Library usage
The Lua bindings for this library closely follow ucglib's object oriented C++ API. Based on the ucg class, you create an object for your display type.
ILI9341 via SPI:
```lua
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = ucg.ili9341_18x240x320_hw_spi(cs, dc, res)
```
This object provides all of ucglib's methods to control the display.
Again, refer to [GraphicsTest.lua](lua_examples/ucglib/GraphicsTest.lua) to get an impression how this is achieved with Lua code. Visit the [ucglib homepage](https://github.com/olikraus/ucglib) for technical details.
#####Displays
To get access to the display constructors, add the desired entries to the display table in [app/include/ucg_config.h](app/include/ucg_config.h):
```c
#define UCG_DISPLAY_TABLE \
UCG_DISPLAY_TABLE_ENTRY(ili9341_18x240x320_hw_spi, ucg_dev_ili9341_18x240x320, ucg_ext_ili9341_18) \
UCG_DISPLAY_TABLE_ENTRY(st7735_18x128x160_hw_spi, ucg_dev_st7735_18x128x160, ucg_ext_st7735_18) \
```
#####Fonts
ucglib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in [app/include/ucg_config.h](app/include/ucg_config.h) and recompile. Simply add the desired fonts to the font table:
```c
#define UCG_FONT_TABLE \
UCG_FONT_TABLE_ENTRY(font_7x13B_tr) \
UCG_FONT_TABLE_ENTRY(font_helvB12_hr) \
UCG_FONT_TABLE_ENTRY(font_helvB18_hr) \
UCG_FONT_TABLE_ENTRY(font_ncenR12_tr) \
UCG_FONT_TABLE_ENTRY(font_ncenR14_hr)
```
They'll be available as `ucg.<font_name>` in Lua.
####Control a WS2812 based light strip
```lua
-- set the color of one LED on GPIO2 to red

View File

@ -74,7 +74,7 @@ static int ICACHE_FLASH_ATTR bmp085_init(lua_State* L) {
bmp085_data.MC = r16(bmp085_i2c_id, 0xBC);
bmp085_data.MD = r16(bmp085_i2c_id, 0xBE);
return 1;
return 0;
}
static uint32_t bmp085_temperature_raw_b5(void) {
@ -128,7 +128,7 @@ static int32_t ICACHE_FLASH_ATTR bmp085_pressure_raw(int oss) {
p3 = r8u(bmp085_i2c_id, 0xF8);
p = (p1 << 16) | (p2 << 8) | p3;
p = p >> (8 - oss);
return p;
}
@ -159,7 +159,7 @@ static int ICACHE_FLASH_ATTR bmp085_lua_pressure(lua_State* L) {
oss = 3;
}
}
p = bmp085_pressure_raw(oss);
B5 = bmp085_temperature_raw_b5();

42
docs/css/extra.css Normal file
View File

@ -0,0 +1,42 @@
blockquote {
padding: 0 15px;
color: #777;
border-left: 4px solid #ddd;
}
.rst-content blockquote {
margin: 0;
}
/*shifts the nested subnav label to the left to align it with the regular nav item labels*/
ul.subnav ul.subnav span {
padding-left: 1.3em;
}
body {
font-size: 100%;
}
p {
line-height: 20px;
margin-bottom: 16px;
}
h1, h2 {
border-bottom: 1px solid #eee;
line-height: 1.2;
margin-top: 1.2em;
margin-bottom: 16px;
}
h3, h4, h5, h6 {
margin: 1em 0 0.7em 0;
}
code {
font-size: 85%;
margin-right: 3px;
}
table.docutils td code {
font-size: 100%;
}
.wy-plain-list-disc, .rst-content .section ul, .rst-content .toctree-wrapper ul, article ul {
line-height: 20px;
margin-bottom: 16px;
}

6
docs/de/index.md Normal file
View File

@ -0,0 +1,6 @@
# NodeMCU Dokumentation
NodeMCU ist eine [eLua](http://www.eluaproject.net/)-basierende firmware für den [ESP8266 WiFi SOC von Espressif](http://espressif.com/en/products/esp8266/). Dies ist ein Partnerprojekt für die beliebten [NodeMCU dev kits](https://github.com/nodemcu/nodemcu-devkit-v1.0) - open source NodeMCU boards mit ESP8266-12E chips.
Diese firmware nutzt das Espressif NON-OS SDK, das Dateisystem basiert auf [spiffs](https://github.com/pellepl/spiffs).

10
docs/en/build.md Normal file
View File

@ -0,0 +1,10 @@
There are essentially three ways to build your NodeMCU firmware: cloud build service, Docker image, dedicated Linux environment (possibly VM).
## Cloud Build Service
NodeMCU "application developers" just need a ready-made firmware. There's a [cloud build service](http://nodemcu-build.com/) with a nice UI and configuration options for them.
## Docker Image
Occasional NodeMCU firmware hackers don't need full control over the complete tool chain. They might not want to setup a Linux VM with the build environment. Docker to the rescue. Give [Docker NodeMCU build](https://hub.docker.com/r/marcelstoer/nodemcu-build/) a try.
## Linux Build Environment
NodeMCU firmware developers commit or contribute to the project on GitHub and might want to build their own full fledged build environment with the complete tool chain. There is a [post in the esp8266.com Wiki](http://www.esp8266.com/wiki/doku.php?id=toolchain#how_to_setup_a_vm_to_host_your_toolchain) that describes this.

358
docs/en/faq.md Normal file
View File

@ -0,0 +1,358 @@
# FAQ
**# # # Work in Progress # # #**
*This was started by [Terry Ellison](https://github.com/TerryE) as an unofficial FAQ in mid 2015. It never became officially official and it is in need of an overhaul, see [#937](https://github.com/nodemcu/nodemcu-firmware/issues/937). Yet, it is still very valuable and is, therefore, included here.*
## What is this FAQ for?
This FAQ does not aim to help you to learn to program or even how to program in Lua. There are plenty of resources on the Internet for this, some of which are listed in [Where to start](#where-to-start). What this FAQ does is to answer some of the common questions that a competent Lua developer would ask in learning how to develop Lua applications for the ESP8266 based boards running the [NodeMcu](http://NodeMCU.com/index_en.html) firmware.
## Lua Language
### Where to start
The NodeMCU firmware implements Lua 5.1 over the Espressif SDK for its ESP8266 SoC and the IoT modules based on this.
* The official lua.org **[Lua Language specification](http://www.lua.org/manual/5.1/manual.html)** gives a terse but complete language specification.
* Its [FAQ](http://www.lua.org/faq.html) provides information on Lua availability and licensing issues.
* The **[unofficial Lua FAQ](http://www.luafaq.org/)** provides a lot of useful Q and A content, and is extremely useful for those learning Lua as a second language.
* The [Lua User's Wiki](http://lua-users.org/wiki/) gives useful example source and relevant discussion. In particular, its [Lua Learning Lua](http://lua-users.org/wiki/Learning) section is a good place to start learning Lua.
* The best book to learn Lua is *Programming in Lua* by Roberto Ierusalimschy, one of the creators of Lua. It's first edition is available free [online](http://www.lua.org/pil/contents.html) . The second edition was aimed at Lua 5.1, but is out of print. The third edition is still in print and available in paperback. It contains a lot more material and clearly identifies Lua 5.1 vs Lua 5.2 differences. **This third edition is widely available for purchase and probably the best value for money**. References of the format [PiL **n.m**] refer to section **n.m** in this edition.
* The Espressif ESP8266 architecture is closed source, but the Espressif SDK itself is continually being updated so the best way to get the documentation for this is to [google Espressif IoT SDK Programming Guide](https://www.google.co.uk/search?q=Espressif+IoT+SDK+Programming+Guide) or to look at the Espressif [downloads forum](http://bbs.espressif.com/viewforum.php?f=5) .
* The **[NodeMCU documentation](http://www.NodeMCU.com/docs/)** is available online. However, please remember that the development team are based in China, and English is a second language, so the documentation needs expanding and be could improved with technical proofing.
* As with all Open Source projects the source for the NodeMCU firmware is openly available on the [GitHub NodeMCU-firmware](https://github.com/NodeMCU/NodeMCU-firmware) repository.
### How is NodeMCU Lua different to standard Lua?
Whilst the Lua standard distribution includes a host stand-alone Lua interpreter, Lua itself is primarily an *extension language* that makes no assumptions about a "main" program: Lua works embedded in a host application to provide a powerful, light-weight scripting language for use within the application. This host application can then invoke functions to execute a piece of Lua code, can write and read Lua variables, and can register C functions to be called by Lua code. Through the use of C functions, Lua can be augmented to cope with a wide range of different domains, thus creating customized programming languages sharing a syntactical framework.
The ESP8266 was designed and is fabricated in China by [Espressif Systems](http://espressif.com/new-sdk-release/). Espressif have also developed and released a companion software development kit (SDK) to enable developers to build practical IoT applications for the ESP8266. The SDK is made freely available to developers in the form of binary libraries and SDK documentation. However this is in a *closed format*, with no developer access to the source files, so ESP8266 applications *must* rely solely on the SDK API (and the somewhat Spartan SDK API documentation).
The NodeMCU Lua firmware is an ESP8266 application and must therefore be layered over the ESP8266 SDK. However, the hooks and features of Lua enable it to be seamlessly integrated without loosing any of the standard Lua language features. The firmware has replaced some standard Lua modules that don't align well with the SDK structure with ESP8266-specific versions. For example, the standard `io` and `os` libraries don't work, but have been largely replaced by the NodeMCU `node` and `file` libraries. The `debug` and `math` libraries have also been omitted to reduce the runtime footprint.
NodeMCU Lua is based on [eLua](http://www.eluaproject.net/overview), a fully featured implementation of Lua 5.1 that has been optimized for embedded system development and execution to provide a scripting framework that can be used to deliver useful applications within the limited RAM and Flash memory resources of embedded processors such as the ESP8266. One of the main changes introduced in the eLua fork is to use read-only tables and constants wherever practical for library modules. On a typical build this approach reduces the RAM footprint by some 20-25KB and this makes a Lua implementation for the ESP8266 feasible. This technique is called LTR and this is documented in detail in an eLua technical paper: [Lua Tiny RAM](http://www.eluaproject.net/doc/master/en_arch_ltr.html).
The mains impacts of the ESP8266 SDK and together with its hardware resource limitations are not in the Lua language implementation itself, but in how *application programmers must approach developing and structuring their applications*. As discussed in detail below, the SDK is non-preemptive and event driven. Tasks can be associated with given events by using the SDK API to registering callback functions to the corresponding events. Events are queued internally within the SDK, and it then calls the associated tasks one at a time, with each task returning control to the SDK on completion. *The SDK states that if any tasks run for more than 10 mSec, then services such as Wifi can fail.*
The NodeMCU libraries act as C wrappers around registered Lua callback functions to enable these to be used as SDK tasks. ***You must therefore use an Event-driven programming style in writing your ESP8266 Lua programs***. Most programmers are used to writing in a procedural style where there is a clear single flow of execution, and the program interfaces to operating system services by a set of synchronous API calls to do network I/O, etc. Whilst the logic of each individual task is procedural, this is not how you code up ESP8266 applications.
## ESP8266 Specifics
### How is coding for the ESP8266 the same as standard Lua?
* This is a fully featured Lua 5.1 implementation so all standard Lua language constructs and data types work.
* The main standard Lua libraries -- `core`, `coroutine`, `string` and `table` are implemented.
### How is coding for the ESP8266 different to standard Lua?
* The ESP8266 use onchip RAM and offchip Flash memory connected using a dedicated SPI interface. Both of these are *very* limited (when compared to systems than most application programmer use). The SDK and the Lua firmware already use the majority of this resource: the later build versions keep adding useful functionality, and unfortunately at an increased RAM and Flash cost, so depending on the build version and the number of modules installed the runtime can have as little as 17KB RAM and 40KB Flash available at an application level. This Flash memory is formatted an made available as a **SPI Flash File System (SPIFFS)** through the `file` library.
* However, if you choose to use a custom build, for example one which uses integer arithmetic instead of floating point, and which omits libraries that aren't needed for your application, then this can help a lot doubling these available resources. (See Marcel Stör's excellent [custom build tool](http://frightanic.com/NodeMCU-custom-build/) that he discusses in [this forum topic](http://www.esp8266.com/viewtopic.php?f=23&t=3001)). Even so, those developers who are used to dealing in MB or GB of RAM and file systems can easily run out of these resources. Some of the techniques discussed below can go a long way to mitigate this issue.
* Current versions of the ESP8266 run the SDK over the native hardware so there is no underlying operating system to capture errors and to provide graceful failure modes, so system or application errors can easily "PANIC" the system causing it to reboot. Error handling has been kept simple to save on the limited code space, and this exacerbates this tendency. Running out of a system resource such as RAM will invariably cause a messy failure and system reboot.
* There is currently no `debug` library support. So you have to use 1980s-style "binary-chop" to locate errors and use print statement diagnostics though the systems UART interface. (This omission was largely because of the Flash memory footprint of this library, but there is no reason in principle why we couldn't make this library available in the near future as an custom build option).
* The LTR implementation means that you can't easily extend standard libraries as you can in normal Lua, so for example an attempt to define `function table.pack()` will cause a runtime error because you can't write to the global `table`. (Yes, there are standard sand-boxing techniques to achieve the same effect by using metatable based inheritance, but if you try to use this type of approach within a real application, then you will find that you run out of RAM before you implement anything useful.)
* There are standard libraries to provide access to the various hardware options supported by the hardware: WiFi, GPIO, One-wire, I²C, SPI, ADC, PWM, UART, etc.
* The runtime system runs in interactive-mode. In this mode it first executes any `init.lua` script. It then "listens" to the serial port for input Lua chunks, and executes them once syntactically complete. There is no `luac` or batch support, although automated embedded processing is normally achieved by setting up the necessary event triggers in the `init.lua` script.
* The various libraries (`net`, `tmr`, `wifi`, etc.) use the SDK callback mechanism to bind Lua processing to individual events (for example a timer alarm firing). Developers should make full use of these events to keep Lua execution sequences short. *If any individual task takes too long to execute then other queued tasks can time-out and bad things start to happen.*
* Non-Lua processing (e.g. network functions) will usually only take place once the current Lua chunk has completed execution. So any network calls should be viewed at an asynchronous request. A common coding mistake is to assume that they are synchronous, that is if two `socket:send()` are on consecutive lines in a Lua programme, then the first has completed by the time the second is executed. This is wrong. Each `socket:send()` request simply queues the send operation for dispatch. Neither will start to process until the Lua code has return to is calling C function. Stacking up such requests in a single Lua task function burns scarce RAM and can trigger a PANIC. This true for timer, network, and other callbacks. It is even the case for actions such as requesting a system restart, as can be seen by the following example:
```lua
node.restart(); for i = 1, 20 do print("not quite yet -- ",i); end
```
* You therefore *have* to implement ESP8266 Lua applications using an event driven approach. You have to understand which SDK API requests schedule asynchronous processing, and which define event actions through Lua callbacks. Yes, such an event-driven approach makes it difficult to develop procedurally structured applications, but it is well suited to developing the sorts of application that you will typically want to implement on an IoT device.
### So how does the SDK event / tasking system work in Lua?
* The SDK employs an event-driven and task-oriented architecture for programming at an applications level.
* The SDK uses a startup hook `void user_init(void)`, defined by convention in the C module `user_main.c`, which it invokes on boot. The `user_init()` function can be used to do any initialisation required and to call the necessary timer alarms or other SDK API calls to bind and callback routines to implement the tasks needed in response to any system events.
* The API provides a set of functions for declaring application functions (written in C) as callbacks to associate application tasks with specific hardware and timer events. These are non-preemptive at an applications level.
* Whilst the SDK provides a number of interrupt driven device drivers, the hardware architecture severely limits the memory available for these drivers, so writing new device drivers is not a viable options for most developers
* The SDK interfaces internally with hardware and device drivers to queue pending events.
* The registered callback routines are invoked sequentially with the associated C task running to completion uninterrupted.
* In the case of Lua, these C tasks are typically functions within the Lua runtime library code and these typically act as C wrappers around the corresponding developer-provided Lua callback functions. An example here is the Lua `tmr.alarm(id, interval, repeat, callback)` function. The calls a function in the `tmr` library which registers a C function for this alarm using the SDK, and when this C function is called it then invokes the Lua callback.
The NodeMCU firmware simply mirrors this structure at a Lua scripting level:
* A startup module `init.lua` is invoked on boot. This function module can be used to do any initialisation required and to call the necessary timer alarms or libary calls to bind and callback routines to implement the tasks needed in response to any system events.
* The Lua libraries provide a set of functions for declaring application functions (written in Lua) as callbacks (which are stored in the [Lua registry](#so-how-is-the-lua-registry-used-and-why-is-this-important)) to associate application tasks with specific hardware and timer events. These are non-preemptive at an applications level.
* The Lua libraries work in consort with the SDK to queue pending events and invoke any registered Lua callback routines, which then run to completion uninterrupted.
* Excessively long-running Lua functions can therefore cause other system functions and services to timeout, or allocate memory to buffer queued data, which can then trigger either the watchdog timer or memory exhaustion, both of which will ultimately cause the system to reboot.
* By default, the Lua runtime also 'listens' to UART 0, the serial port, in interactive mode and will execute any Lua commands input through this serial port.
This event-driven approach is very different to a conventional procedural implementation of Lua.
Consider a simple telnet example given in `examples/fragment.lua`:
```lua
s=net.createServer(net.TCP)
s:listen(23,function(c)
con_std = c
function s_output(str)
if(con_std~=nil) then
con_std:send(str)
end
end
node.output(s_output, 0)
c:on("receive",function(c,l) node.input(l) end)
c:on("disconnection",function(c)
con_std = nil
node.output(nil)
end)
end)
```
This example defines five Lua functions:
| Function | Defined in | Parameters | Callback? |
|-----------|------------|------------|-----------|
| Main | Outer module | ... (Not used) | |
| Connection listener | Main | c (connection socket) | |
| s_output | Connection listener | str | Yes |
| On Receive| Connection listener | c, l (socket, input) | Yes |
| On Disconnect | Connection listener | c (socket) | Yes |
`s`, `con_std` and `s_output` are global, and no [upvalues](#why-is-it-importance-to-understand-how-upvalues-are-implemented-when-programming-for-the-esp8266) are used. There is no "correct" order to define these in, but we could reorder this code for clarity (though doing this adds a few extra globals) and define these functions separately one another. However, let us consider how this is executed:
* The outer module is compiled including the four internal functions.
* `Main` is then assigning the created `net.createServer()` to the global `s`. The `connection listener` closure is created and bound to a temporary variable which is then passed to the `socket.listen()` as an argument. The routine then exits returning control to the firmware.
* When another computer connects to port 23, the listener handler retrieves the reference to then connection listener and calls it with the socket parameter. This function then binds the s_output closure to the global `s_output`, and registers this function with the `node.output` hook. Likewise the `on receive` and `on disconnection` are bound to temporary variables which are passed to the respective on handlers. We now have four Lua function registered in the Lua runtime libraries associated with four events. This routine then exits returning control to the firmware.
* When a record is received, the on receive handler within the net library retrieves the reference to the `on receive` Lua function and calls it passing it the record. This routine then passes this to the `node.input()` and exits returning control to the firmware.
* The `node.input` handler polls on an 80 mSec timer alarm. If a compete Lua chunk is available (either via the serial port or node input function), then it executes it and any output is then passed to the `note.output` handler. which calls `s_output` function. Any pending sends are then processed.
* This cycle repeats until the other computer disconnects, and `net` library disconnection handler then calls the Lua `on disconnect` handler. This Lua routine dereferences the connected socket and closes the `node.output` hook and exits returning control to the disconnect handler which garbage collects any associated sockets and registered on handlers.
Whilst this is all going on, The SDK can (and often will) schedule other event tasks in between these Lua executions (e.g. to do the actual TCP stack processing). The longest individual Lua execution in this example is only 18 bytecode instructions (in the main routine).
Understanding how the system executes your code can help you structure it better and improve memory usage. Each event task is established by a callback in an API call in an earlier task.
### So what Lua library functions enable the registration of Lua callbacks?
SDK Callbacks include:
| Lua Module | Functions which define or remove callbacks |
|------------|--------------------------------------------|
| tmr | `alarm(id, interval, repeat, function())` |
| node | `key(type, function())`, `output(function(str), serial_debug)` |
| wifi | `startsmart(chan, function())`, `sta.getap(function(table))` |
| net.server | `sk:listen(port,[ip],function(socket))` |
| net | `sk:on(event, function(socket, [, data]))`, `sk:send(string, function(sent))`, `sk:dns(domain, function(socket,ip))` |
| gpio | `trig(pin, type, function(level))` |
| mqqt | `client:m:on(event, function(conn[, topic, data])` |
| uart | `uart.on(event, cnt, [function(data)], [run_input])` |
### So how is context passed between Lua event tasks?
* It is important to understand that any event callback task is associated with a single Lua function. This function is executed from the relevant NodeMCU library C code using a `lua_call()`. Even system initialisation which executes the `dofile("init.lua")` can be treated as a special case of this. Each function can invoke other functions and so on, but it must ultimate return control to the C library code.
* By their very nature Lua `local` variables only exist within the context of an executing Lua function, and so all locals are destroyed between these `lua_call()` actions. *No locals are retained across events*.
* So context can only be passed between event routines by one of three mechanisms:
* **Globals** are by nature globally accessible. Any global will persist until explicitly dereference by reassigning `nil` to it. Globals can be readily enumerated by a `for k,v in pairs(_G) do` so their use is transparent.
* The **File system** is a special case of persistent global, so there is no reason in principle why it can't be used to pass context. However the ESP8266 file system uses flash memory and this has a limited write cycle lifetime, so it is best to avoid using the file system to store frequently changing content except as a mechanism of last resort.
* **Upvalues**. When a function is declared within an outer function, all of the local variables in the outer scope are available to the inner function. Since all functions are stored by reference the scope of the inner function might outlast the scope of the outer function, and the Lua runtime system ensures that any such references persist for the life of any functions that reference it. This standard feature of Lua is known as *closure* and is described in [Pil 6]. Such values are often called *upvalues*. Functions which are global or [[#So how is the Lua Registry used and why is this important?|registered]] callbacks will persist between event routines, and hence any upvalues referenced by them can be used for passing context.
### So how is the Lua Registry used and why is this important?
So all Lua callbacks are called by C wrapper functions that are themselves callback activated by the SDK as a result of a given event. Such C wrapper functions themselves frequently need to store state for passing between calls or to other wrapper C functions. The Lua registry is simply another Lua table which is used for this purpose, except that it is hidden from direct Lua access. Any content that needs to be saved is created with a unique key. Using a standard Lua table enables standard garbage collection algorithms to operate on its content.
Note that we have identified a number of cases where library code does not correctly clean up Registry content when closing out an action, leading to memory leaks.
### Why is it importance to understand how upvalues are implemented when programming for the ESP8266?
Routines directly or indirectly referenced in the globals table, **_G**, or in the Lua Registry may use upvalues. The number of upvalues associated with a given routine is determined by the compiler and a vector is allocated when the closure is bound to hold these references. Each upvalues is classed as open or closed. All upvalues are initially open which means that the upvalue references back to the outer functions's register set. However, upvalues must be able to outlive the scope of the outer routine where they are declared as a local variable. The runtime VM does this by adding extra checks when executing a function return to scan any defined closures within its scope for back references and allocate memory to hold the upvalue and points the upvalue's reference to this. This is known as a closed upvalue.
This processing is a mature part of the Lua 5.x runtime system, and for normal Lua applications development this "behind-the-scenes" magic ensures that upvalues just work as any programmer might expect. Sufficient garbage collector metadata is also stored so that these hidden values will be garbage collected correctly *when properly dereferenced*. However allocating these internal structures is quite expensive in terms of memory, and this hidden overhead is hard to track or to understand. If you are developing a Lua application for a PC where the working RAM for an application is measured in MB, then this isn't really an issue. However, if you are developing an application for the ESP8266 where you might have 20 KB for your program and data, this could prove a killer.
One further complication is that some library functions don't correctly dereference expired callback references and as a result their upvalues may not be correctly garbage collected (though we are tracking this down and hopefully removing this issue). This will all be manifested as a memory leak. So using upvalues can cause more frequent and difficult to diagnose PANICs during testing. So my general recommendation is still to stick to globals for this specific usecase of passing context between event callbacks, and `nil` them when you have done with them.
### Can I encapsulate actions such as sending an email in a Lua function?
Think about the implications of these last few answers.
* An action such as composing and sending an email involves a message dialogue with a mail server over TCP. This in turn requires calling multiple API calls to the SDK and your Lua code must return control to the C calling library for this to be scheduled, otherwise these requests will just queue up, you'll run out of RAM and your application will PANIC.
* Hence it is simply ***impossible*** to write a Lua module so that you can do something like:
```lua
-- prepare message
status = mail.send(to, subject, body)
-- move on to next phase of processing.
```
* But you could code up a event-driven task to do this and pass it a callback to be executed on completion of the mail send, something along the lines of the following. Note that since this involves a lot of asynchronous processing and which therefore won't take place until you've returned control to the calling library C code, you will typically execute this as the last step in a function and therefore this is best done as a tailcall [PiL 6.3].
```lua
-- prepare message
local ms = require("mail_sender")
return ms.send(to, subject, body, function(status) loadfile("process_next.lua")(status) end)
```
* Building an application on the ESP8266 is a bit like threading pearls onto a necklace. Each pearl is an event task which must be small enough to run within its RAM resources and the string is the variable context that links the pearls together.
### When and why should I avoid using tmr.delay()?
If you are used coding in a procedural paradigm then it is understandable that you consider using `tmr.delay()` to time sequence your application. However as discussed in the previous section, with NodeMCU Lua you are coding in an event-driven paradigm.
If you look at the `app/modules/tmr.c` code for this function, then you will see that it executes a low level `ets_delay_us(delay)`. This function isn't part of the NodeMCU code or the SDK; it's actually part of the xtensa-lx106 boot ROM, and is a simple timing loop which polls against the internal CPU clock. It does this with interrupts disabled, because if they are enabled then there is no guarantee that the delay will be as requested.
`tmr.delay()` is really intended to be used where you need to have more precise timing control on an external hardware I/O (e.g. lifting a GPIO pin high for 20 μSec). It will achieve no functional purpose in pretty much every other usecase, as any other system code-based activity will be blocked from execution; at worst it will break your application and create hard-to-diagnose timeout errors.
The latest SDK includes a caution that if any (callback) task runs for more than 10 mSec, then the Wifi and TCP stacks might fail, so if you want a delay of more than 8 mSec or so, then *using `tmr.delay()` is the wrong approach*. You should be using a timer alarm or another library callback, to allow the other processing to take place. As the NodeMCU documentation correctly advises (translating Chinese English into English): *`tmr.delay()` will make the CPU work in non-interrupt mode, so other instructions and interrupts will be blocked. Take care in using this function.*
### How do I avoid a PANIC loop in init.lua?
Most of us have fallen into the trap of creating an `init.lua` that has a bug in it, which then causes the system to reboot and hence gets stuck in a reboot loop. If you haven't then you probably will do so at least once.
* When this happens, the only robust solution is to reflash the firmware.
* The simplest way to avoid having to do this is to keep the `init.lua` as simple as possible -- say configure the wifi and then start your app using a one-time `tmr.alarm()` after a 2-3 sec delay. This delay is long enough to issue a `file.remove("init.lua")` through the serial port and recover control that way.
* Also it is always best to test any new `init.lua` by creating it as `init_test.lua`, say, and manually issuing a `dofile("init_test.lua")` through the serial port, and then only rename it when you are certain it is working as you require.
## Techniques for Reducing RAM and SPIFFS footprint
### How do I minimise the footprint of an application?
* Perhaps the simplest aspect of reducing the footprint of an application is to get its scope correct. The ESP8266 is an IoT device and not a general purpose system. It is typically used to attach real-world monitors, controls, etc. to an intranet and is therefore designed to implement functions that have limited scope. We commonly come across developers who are trying to treat the ESP8266 as a general purpose device and can't understand why their application can't run.
* The simplest and safest way to use IoT devices is to control them through a dedicated general purpose system on the same network. This could be a low cost system such as a [RaspberryPi (RPi)](https://www.raspberrypi.org/) server, running your custom code or an open source home automation (HA) application. Such systems have orders of magnitude more capacity than the ESP8266, for example the RPi has 2GB RAM and its SD card can be up to 32GB in capacity, and it can support the full range of USB-attached disk drives and other devices. It also runs a fully featured Linux OS, and has a rich selection of applications pre configured for it. There are plenty of alternative systems available in this under $50 price range, as well as proprietary HA systems which can cost 10-50 times more.
* Using a tiered approach where all user access to the ESP8266 is passed through a controlling server means that the end-user interface (or smartphone connector), together with all of the associated validation and security can be implemented on a system designed to have the capacity to do this. This means that you can limit the scope of your ESP8266 application to a limited set of functions being sent to or responding to requests from this system.
* *If you are trying to implement a user-interface or HTTP webserver in your ESP8266 then you are really abusing its intended purpose. When it comes to scoping your ESP8266 applications, the adage **K**eep **I**t **S**imple **S**tupid truly applies.*
### How do I minimise the footprint of an application on the file system
* It is possible to write Lua code in a very compact format which is very dense in terms of functionality per KB of source code.
* However if you do this then you will also find it extremely difficult to debug or maintain your application.
* A good compromise is to use a tool such as [LuaSrcDiet](http://luaforge.net/projects/luasrcdiet/), which you can use to compact production code for downloading to the ESP8266:
* Keep a master repository of your code on your PC or a cloud-based versioning repository such as [GitHub](https://github.com/)
* Lay it out and comment it for ease of maintenance and debugging
* Use a package such as [Esplorer](https://github.com/4refr0nt/ESPlorer) to download modules that you are debugging and to test them.
* Once the code is tested and stable, then compress it using LuaSrcDiet before downloading to the ESP8266. Doing this will reduce the code footprint on the SPIFFS by 2-3x.
* Consider using `node.compile()` to pre-compile any production code. This removes the debug information from the compiled code reducing its size by roughly 40%. (However this is still perhaps 1.5-2x larger than a LuaSrcDiet-compressed source format, so if SPIFFS is tight then you might consider leaving less frequently run modules in Lua format. If you do a compilation, then you should consider removing the Lua source copy from file system as there's little point in keeping both on the ESP8266.
### How do I minimise the footprint of running application?
* The Lua Garbage collector is very aggressive at scanning and recovering dead resources. It uses an incremental mark-and-sweep strategy which means that any data which is not ultimately referenced back to the Globals table, the Lua registry or in-scope local variables in the current Lua code will be collected.
* Setting any variable to `nil` dereferences the previous context of that variable. (Note that reference-based variables such as tables, strings and functions can have multiple variables referencing the same object, but once the last reference has been set to `nil`, the collector will recover the storage.
* Unlike other compile-on-load languages such as PHP, Lua compiled code is treated the same way as any other variable type when it comes to garbage collection and can be collected when fully dereferenced, so that the code-space can be reused.
* Lua execution is intrinsically divided into separate event tasks with each bound to a Lua callback. This, when coupled with the strong dispose on dereference feature, means that it is very easy to structure your application using an classic technique which dates back to the 1950s known as Overlays.
* Various approaches can be use to implement this. One is described by DP Whittaker in his [Massive memory optimization: flash functions](http://www.esp8266.com/viewtopic.php?f=19&t=1940) topic. Another is to use *volatile modules*. There are standard Lua templates for creating modules, but the `require()` library function creates a reference for the loaded module in the `package.loaded` table, and this reference prevents the module from being garbage collected. To make a module volatile, you should remove this reference to the loaded module by setting its corresponding entry in `package.loaded` to `nil`. You can't do this in the outermost level of the module (since the reference is only created once execution has returned from the module code), but you can do it in any module function, and typically an initialisation function for the module, as in the following example:
```lua
local s=net.createServer(net.TCP)
s:listen(80,function(c) require("connector").init(c) end)
```
* **`connector.lua`** would be a standard module pattern except that the `M.init()` routine must include the lines
```lua
local M, module = {}, ...
...
function M.init(csocket)
package.loaded[module]=nil
...
end
--
return M
```
* This approach ensures that the module can be fully dereferenced on completion. OK, in this case, this also means that the module has to be reloaded on each TCP connection to port 80; however, loading a compiled module from SPIFFS only takes a few mSec, so surely this is an acceptable overhead if it enables you to break down your application into RAM-sized chunks. Note that `require()` will automatically search for `connector.lc` followed by `connector.lua`, so the code will work for both source and compiled variants.
* Whilst the general practice is for a module to return a table, [PiL 15.1] suggests that it is sometimes appropriate to return a single function instead as this avoids the memory overhead of an additional table. This pattern would look as follows:
```lua
--
local s=net.createServer(net.TCP)
s:listen(80,function(c) require("connector")(c) end)
```
```lua
local module = _ -- this is a situation where using an upvalue is essential!
return function (csocket)
package.loaded[module]=nil
module = nil
...
end
```
* Also note that you should ***not*** normally code this up listener call as the following because the RAM now has to accommodate both the module which creates the server *and* the connector logic.
```lua
...
local s=net.createServer(net.TCP)
local connector = require("connector") -- don't do this unless you've got the RAM available!
s:listen(80,connector)
```
### How do I reduce the size of my compiled code?
Note that there are two methods of saving compiled Lua to SPIFFS:
- The first is to use `node.compile()` on the `.lua` source file, which generates the equivalent bytecode `.lc` file. This approach strips out all the debug line and variable information.
- The second is to use `loadfile()` to load the source file into memory, followed by `string.dump()` to convert it in-memory to a serialised load format which can then be written back to a `.lc` file. This approach creates a bytecode file which retains the debug information.
The memory footprint of the bytecode created by method (2) is the same as when executing source files directly, but the footprint of bytecode created by method (1) is typically **60% of this size**, because the debug information is almost as large as the code itself. So using `.lc` files generated by `node.compile()` considerably reduces code size in memory -- albeit with the downside that any runtime errors are extremely limited.
In general consider method (1) if you have stable production code that you want to run in as low a RAM footprint as possible. Yes, method (2) can be used if you are still debugging, but you will probably be changing this code quite frequently, so it is easier to stick with `.lua` files for code that you are still developing.
Note that if you use `require("XXX")` to load your code then this will automatically search for `XXX.lc` then `XXX.lua` so you don't need to include the conditional logic to load the bytecode version if it exists, falling back to the source version otherwise.
### How do I get a feel for how much memory my functions use?
* You should get an overall understanding of the VM model if you want to make good use of the limited resources available to Lua applications. An essential reference here is [A No Frills Introduction to Lua 5.1 VM Instructions](http://luaforge.net/docman/83/98/ANoFrillsIntroToLua51VMInstructions.pdf) . This explain how the code generator works, how much memory overhead is involved with each table, function, string etc..
* You can't easily get a bytecode listing of your ESP8266 code; however there are two broad options for doing this:
* **Generate a bytecode listing on your development PC**. The Lua 5.1 code generator is basically the same on the PC and on the ESP8266, so whilst it isn't identical, using the standard Lua batch compiler `luac` against your source on your PC with the `-l -s` option will give you a good idea of what your code will generate. The main difference between these two variants is the size_t for ESP8266 is 4 bytes rather than the 8 bytes size_t found on modern 64bit development PCs; and the eLua variants generate different access references for ROM data types. If you want to see what the `string.dump()` version generates then drop the `-s` option to retain the debug information.
* **Upload your `.lc` files to the PC and disassemble then there**. There are a number of Lua code disassemblers which can list off the compiled code that you application modules will generate, `if` you have a script to upload files from your ESP8266 to your development PC. I use [ChunkSpy](http://luaforge.net/projects/chunkspy/) which can be downloaded [here](http://files.luaforge.net/releases/chunkspy/chunkspy/ChunkSpy-0.9.8/ChunkSpy-0.9.8.zip) , but you will need to apply the following patch so that ChunkSpy understands eLua data types:
```diff
--- a/ChunkSpy-0.9.8/5.1/ChunkSpy.lua 2015-05-04 12:39:01.267975498 +0100
+++ b/ChunkSpy-0.9.8/5.1/ChunkSpy.lua 2015-05-04 12:35:59.623983095 +0100
@@ -2193,6 +2193,9 @@
config.AUTO_DETECT = true
elseif a == "--brief" then
config.DISPLAY_BRIEF = true
+ elseif a == "--elua" then
+ config.LUA_TNUMBER = 5
+ config.LUA_TSTRING = 6
elseif a == "--interact" then
perform = ChunkSpy_Interact
```
* Your other great friend is to use `node.heap()` regularly through your code.
* Use these tools and play with coding approaches to see how many instructions each typical line of code takes in your coding style. The Lua Wiki gives some general optimisation tips, but in general just remember that these focus on optimising for execution speed and you will be interested mainly in optimising for code and variable space as these are what consumes precious RAM.
### What is the cost of using functions?
Consider the output of `dofile("test1a.lua")` on the following code compared to the equivalent where the function `pnh()` is removed and the extra `print(heap())` statement is placed inline:
```lua
-- test1b.lua
collectgarbage()
local heap = node.heap
print(heap())
local function pnh() print(heap()) end
pnh()
print(heap())
```
|Heap Value | Function Call | Inline |
|-----------|---------------|--------|
| 1 | 20712 | 21064 |
| 2 | 20624 | 21024 |
| 3 | 20576 | 21024 |
Here bigger means less RAM used.
Of course you should still use functions to structure your code and encapsulate common repeated processing, but just bear in mind that each function definition has a relatively high overhead for its header record and stack frame (compared to the 20 odd KB RAM available). *So try to avoid overusing functions. If there are less than a dozen or so lines in the function then you should consider putting this code inline if it makes sense to do so.*
### What other resources are available?
* Install lua and luac on your development PC. This is freely available for Windows, Mac and Linux distributions, but we strongly suggest that you use Lua 5.1 to maintain source compatibility with ESP8266 code. This will allow you not only to unit test some modules on your PC in a rich development environment, but you can also use `luac` to generate a bytecode listing of your code and to validate new code syntactically before downloading to the ESP8266. This will also allow you to develop server-side applications and embedded applications in a common language.
## Firmware and Lua app development
### How to save memory?
* The NodeMCU development team recommends that you consider using a tailored firmware build, which only includes the modules that you plan to use before developing any Lua application. Once you have the ability to make and flash custom builds, the you also have the option of moving time sensitive or logic intensive code into your own custom module. Doing this can save a large amount of RAM as C code can be run directly from Flash memory. If you want an easy-to-use intermediate option then why note try the [cloud based NodeMCU custom build service](http://frightanic.com/NodeMCU-custom-build)?.
## Hardware Specifics
### Why file writes fail all the time on DEVKIT V1.0?
NodeMCU DEVKIT V1.0 uses ESP12-E-DIO(ESP-12-D) module. This module runs the Flash memory in [Dual IO SPI](#whats-the-different-between-dio-and-qio-mode) (DIO) mode. This firmware will not be correctly loaded if you uses old flashtool version, and the filesystem will not work if you used a pre 0.9.6 firmware version (<0.9.5) or old. The easiest way to resolve this problem s update all the firmware and flash tool to current version.
- Use the latest [esptool.py](https://github.com/themadinventor/esptool) with DIO support and command option to flash firmware, or
- Use the latest [NodeMCU flasher](https://github.com/NodeMCU/NodeMCU-flasher) with default option. (You must select the `restore to default` option in advanced menu tab), or
- Use the latest Espressif's flash tool -- see [this Espressif forum topic](http://bbs.espressif.com/viewtopic.php?f=5&t=433) (without auto download support). Use DIO mode and 32M flash size option, and flash latest firmware to 0x00000. Before flashing firmware, remember to hold FLASH button, and press RST button once. Note that the new NodeMCU our firmware download tool, when released, will be capable of flashing firmware automatically without any button presses.
### What's the different between DIO and QIO mode?
<TODO>
### How to use DEVKIT V0.9 on Mac OS X?
<TODO>
### How does DEVKIT use DTR and RTS enter download mode?
<TODO>

31
docs/en/flash.md Normal file
View File

@ -0,0 +1,31 @@
Adafruit provides a really nice [firmware flashing tutorial](https://learn.adafruit.com/building-and-running-micropython-on-the-esp8266/flash-firmware). Below you'll find just the basics for the two popular tools esptool and NodeMCU Flasher.
!!! note "Note:"
Keep in mind that the ESP8266 needs to be put into flash mode before you can flash a new firmware!
To enable ESP8266 firmware flashing GPIO0 pin must be pulled low before the device is reset. Conversely, for a normal boot, GPIO0 must be pulled high or floating.
If you have a [NodeMCU dev kit](https://github.com/nodemcu/nodemcu-devkit-v1.0) then you don't need to do anything, as the USB connection can pull GPIO0 low by asserting DTR and reset your board by asserting RTS.
If you have an ESP-01 or other device without built-in USB, you will need to enable flashing yourself by pulling GPIO0 low or pressing a "flash" switch.
## esptool
> A cute Python utility to communicate with the ROM bootloader in Espressif ESP8266. It is intended to be a simple, platform independent, open source replacement for XTCOM.
Source: [https://github.com/themadinventor/esptool](https://github.com/themadinventor/esptool)
Supported platforms: OS X, Linux, Windows, anything that runs Python
**Running esptool.py**
Run the following command to flash an *aggregated* binary as is produced for example by the [cloud build service](build.md#cloud-build-service) or the [Docker image](build.md#docker-image).
`esptool.py --port <USB-port-with-ESP8266> write_flash 0x00000 <nodemcu-firmware>.bin`
## NodeMCU Flasher
> A firmware Flash tool for NodeMCU...We are working on next version and will use QT framework. It will be cross platform and open-source.
Source: [https://github.com/nodemcu/nodemcu-flasher](https://github.com/nodemcu/nodemcu-flasher)
Supported platforms: Windows

51
docs/en/index.md Normal file
View File

@ -0,0 +1,51 @@
# NodeMCU Documentation
NodeMCU is an [eLua](http://www.eluaproject.net/) based firmware for the [ESP8266 WiFi SOC from Espressif](http://espressif.com/en/products/esp8266/). The firmware is based on the Espressif NON-OS SDK and uses a file system based on [spiffs](https://github.com/pellepl/spiffs). The code repository consists of 98.1% C-code that glues the thin Lua veneer to the SDK.
The NodeMCU *firmware* is a companion project to the popular [NodeMCU dev kits](https://github.com/nodemcu/nodemcu-devkit-v1.0), ready-made open source development boards with ESP8266-12E chips.
## Programming Model
The NodeMCU programming model is similar to that of [Node.js](https://en.wikipedia.org/wiki/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.
```lua
-- a simple HTTP server
srv = net.createServer(net.TCP)
srv:listen(80, function(conn)
conn:on("receive", function(conn, payload)
print(payload)
conn:send("<h1> Hello, NodeMCU.</h1>")
end)
conn:on("sent", function(conn) conn:close() end)
end)
```
```lua
-- connect to WiFi access point
wifi.setmode(wifi.STATION)
wifi.sta.config("SSID", "password")
```
```lua
-- register event callbacks for WiFi events
wifi.sta.eventMonReg(wifi.STA_CONNECTING, function(previous_state)
if(previous_state==wifi.STA_GOTIP) then
print("Station lost connection with access point. Attempting to reconnect...")
else
print("STATION_CONNECTING")
end
end)
```
```lua
-- manipulate hardware like with Arduino
pin = 1
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)
print(gpio.read(pin))
```
## Getting Started
1. [Build the firmeware](build.md) with the modules you need.
1. [Flash the firmware](flash.md) to the chip.
1. [Upload code](upload.md) to the firmware.

39
docs/en/modules/adc.md Normal file
View File

@ -0,0 +1,39 @@
# ADC Module
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, but not both.
The default setting in the NodeMCU firmware can be controlled via user_config.h at compile time, by defining one of ESP_INIT_DATA_ENABLE_READVDD33, ESP_INIT_DATA_ENABLE_READADC or ESP_INIT_DATA_FIXED_VDD33_VALUE. To change the setting at a later date, use Espressif's flash download tool to create a new init data block.
## adc.read()
Samples the ADC.
####Syntax
`adc.read(channel)`
####Parameters
`channel` always 0 on the ESP8266
####Returns
the sampled value (number)
####Example
```lua
val = adc.read(0)
```
## adc.readvdd33()
Reads the system voltage.
####Syntax
`adc.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.

170
docs/en/modules/bit.md Normal file
View File

@ -0,0 +1,170 @@
# bit Module
Bit manipulation support, on 32bit integers.
## bit.arshift()
Arithmetic right shift a number equivalent to `value >> shift` in C.
####Syntax
`bit.arshift(value, shift)`
####Parameters
- `value` the value to shift
- `shift` positions to shift
####Returns
the number shifted right (arithmetically)
## bit.band()
Bitwise AND, equivalent to `val1 & val2 & ... & valn` in C.
####Syntax
`bit.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)
## bit.bit()
Generate a number with a 1 bit (used for mask generation). Equivalent to `1 << position` in C.
####Syntax
`bit.bit(position)`
####Parameters
`position` 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)
## bit.bnot()
Bitwise negation, equivalent to `~value in C.
####Syntax
`bit.bnot(value)`
####Parameters
`value` the number to negate
####Returns
the bitwise negated value of the number
## bit.bor()
Bitwise OR, equivalent to `val1 | val2 | ... | valn` in C.
####Syntax
`bit.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)
## bit.bxor()
Bitwise XOR, equivalent to `val1 ^ val2 ^ ... ^ valn` in C.
####Syntax
`bit.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)
## bit.clear()
Clear bits in a number.
####Syntax
`bit.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)
## bit.isclear()
Test if a given bit is cleared.
####Syntax
`bit.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 othewise
## bit.isset()
Test if a given bit is set.
####Syntax
`bit.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
## bit.lshift()
Left-shift a number, equivalent to `value << shift` in C.
####Syntax
`bit.lshift(value, shift)`
####Parameters
- `value` the value to shift
- `shift` positions to shift
####Returns
the number shifted left
## bit.rshift()
Logical right shift a number, equivalent to `( unsigned )value >> shift` in C.
####Syntax
`bit.rshift(value, shift)`
####Parameters
- `value` the value to shift.
- `shift` positions to shift.
####Returns
the number shifted right (logically)
## bit.set()
Set bits in a number.
####Syntax
`bit.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)

67
docs/en/modules/bmp085.md Normal file
View File

@ -0,0 +1,67 @@
# BMP085 Module
This module provides access to the [BMP085](https://www.sparkfun.com/tutorials/253) temperature and pressure sensor. The module also works with BMP180.
## bmp085.init()
Initializes the module and sets the pin configuration.
#### Syntax
`bmp085.init(sda, scl)`
#### Parameters
- `sda` data pin
- `scl` clock pin
#### Returns
`nil`
## bmp085.temperature()
Samples the sensor and returns the temperature in celsius as an integer multiplied with 10.
#### Syntax
`bmp085.temperature()`
#### Returns
temperature multiplied with 10 (integer)
#### Example
```lua
bmp085.init(1, 2)
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.
#### Syntax
`bmp085.pressure(oversampling_setting)`
#### Parameters
`oversampling_setting` integer that can be 0, 1, 2 or 3
#### Returns
pressure in pascals (integer)
#### Example
```lua
bmp085.init(1, 2)
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.
#### Syntax
`bmp085.pressure_raw(oversampling_setting)`
#### Parameters
`oversampling_setting` integer that can be 0, 1, 2 or 3
#### Returns
raw pressure sampling value (integer)

49
docs/en/modules/cjson.md Normal file
View File

@ -0,0 +1,49 @@
# CJSON Module
The JSON support module. Allows encoding and decoding to/from JSON.
Please note that nested tables can require a lot of memory to encode. To catch out-of-memory errors, use `pcall()`.
## cjson.encode()
Encode a Lua table to a JSON string. For details see the [documentation of the original Lua library](http://kyne.com.au/~mark/software/lua-cjson-manual.html#encode).
####Syntax
`cjson.encode(table)`
####Parameters
`table` data to encode
While it also is possible to encode plain strings and numbers rather than a table, it is not particularly useful to do so.
####Returns
JSON string
####Example
```lua
ok, json = pcall(cjson.encode, {key="value"})
if ok then
print(json)
else
print("failed to encode!")
end
```
## cjson.decode()
Decode a JSON string to a Lua table. For details see the [documentation of the original Lua library](http://kyne.com.au/~mark/software/lua-cjson-manual.html#_decode).
####Syntax
`cjson.decode(str)`
####Parameters
`str` JSON string to decode
####Returns
Lua table representation of the JSON data
####Example
```lua
t = cjson.decode('{"key":"value"}')
for k,v in pairs(t) do print(k,v) end
```

224
docs/en/modules/coap.md Executable file
View File

@ -0,0 +1,224 @@
# CoAP Module
The CoAP module provides a simple implementation according to [CoAP](http://tools.ietf.org/html/rfc7252) protocol.
The basic endpoint server part is based on [microcoap](https://github.com/1248/microcoap), and many other code reference [libcoap](https://github.com/obgm/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 varibles. No observe or discover supported yet.
## Caution
This module is only in the very early stage 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.
#### Syntax
`coap.Client()`
#### Parameters
none
#### Returns
CoAP client
#### Example
```lua
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.
#### Syntax
`coap.Server()`
#### Parameters
none
#### Returns
CoAP server
#### Example
```lua
-- 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.
#### Syntax
`coap.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.
#### Returns
`nil`
## coap.client:put()
Issues a PUT request to the server.
#### Syntax
`coap.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.
#### Returns
`nil`
## coap.client:post()
Issues a POST request to the server.
#### Syntax
`coap.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.
#### Returns
`nil`
## coap.client:delete()
Issues a DELETE request to the server.
#### Syntax
`coap.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.
#### Returns
`nil`
# CoAP Server
## coap.server:listen()
Starts the CoAP server on the given port.
#### Syntax
`coap.server:listen(port[, ip])`
#### Parameters
- `port` server port (number)
- `ip` optional IP address
#### Returns
`nil`
## coap.server:close()
Closes the CoAP server.
#### Syntax
`coap.server:close()`
#### Parameters
none
#### Returns
`nil`
## 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](http://tools.ietf.org/html/rfc7252#section-6) to the client. The endpoint path for varialble is '/v1/v/'.
#### Syntax
`coap.server:var(name[, content_type])`
#### Parameters
- `name` the Lua variable's name
- `content_type` optional, defaults to `coap.TEXT_PLAIN`, see [Content Negotiation](http://tools.ietf.org/html/rfc7252#section-5.5.4)
#### Returns
`nil`
#### Example
```lua
-- 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](http://tools.ietf.org/html/rfc7252#section-6) 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.
#### Syntax
`coap.server:func(name[, content_type])`
#### Parameters
- `name` the Lua function's name
- `content_type` optional, defaults to `coap.TEXT_PLAIN`, see [Content Negotiation](http://tools.ietf.org/html/rfc7252#section-5.5.4)
#### Returns
`nil`
#### Example
```lua
-- 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.
```

110
docs/en/modules/crypto.md Normal file
View File

@ -0,0 +1,110 @@
# crypto Module
The crypto modules provides various functions for working with cryptographic algorithms.
## crypto.hash()
Compute a cryptographic hash of a Lua string.
#### Syntax
`hash = crypto.hash(algo, str)`
#### Parameters
`algo` the hash algorithm to use, case insensitive string
Supported hash algorithms are:
- MD2 (not available by default, has to be explicitly enabled in `app/include/user_config.h`)
- MD5
- SHA1
- SHA256, SHA384, SHA512 (unless disabled in `app/include/user_config.h`)
#### Returns
A binary string containing the message digest. To obtain the textual version (ASCII hex characters), please use [`crypto.toHex()`](#cryptotohex ).
#### Example
```lua
print(crypto.toHex(crypto.hash("sha1","abc")))
```
## crypto.hmac()
Compute a [HMAC](https://en.wikipedia.org/wiki/Hash-based_message_authentication_code) (Hashed Message Authentication Code) signature for a Lua string.
#### Syntax
`signature = 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
Supported hash algorithms are:
- MD2 (not available by default, has to be explicitly enabled in `app/include/user_config.h`)
- MD5
- SHA1
- SHA256, SHA384, SHA512 (unless disabled in `app/include/user_config.h`)
#### Returns
A binary string containing the HMAC signature. Use [`crypto.toHex()`](#cryptotohex ) to obtain the textual version.
#### Example
```lua
print(crypto.toHex(crypto.hmac("sha1","abc","mysecret")))
```
## 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.
#### Syntax
`crypto.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 [`crypto.toHex()`](#cryptotohex) to get a textual representation of it.
#### Example
```lua
print(crypto.toHex(crypto.mask("some message to obscure","X0Y7")))
```
## crypto.toBase64()
Provides a Base64 representation of a (binary) Lua string.
#### Syntax
`b64 = crypto.toBase64(binary)`
#### Parameters
`binary` input string to Base64 encode
#### Return
A Base64 encoded string.
#### Example
```lua
print(crypto.toBase64(crypto.hash("sha1","abc")))
```
## crypto.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.
#### Syntax
`hexstr = crypto.toHex(binary)`
#### Parameters
`binary` input string to get hex representation for
#### Returns
An ASCII hex string.
#### Example
```lua
print(crypto.toHex(crypto.hash("sha1","abc")))
```

93
docs/en/modules/dht.md Normal file
View File

@ -0,0 +1,93 @@
# dht Module
## Constants
`dht.OK` (0), `dht.ERROR_CHECKSUM` (1), `dht.ERROR_TIMEOUT` (2)
## dht.read()
Read all kinds of DHT sensors, including DHT11, 21, 22, 33, 44 humidity temperature combo sensor.
#### Syntax
`dht.read(pin)`
#### Parameters
`pin` 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 "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
```lua
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_deci,
math.floor(humi),
humi_deci
))
-- 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.
#### Syntax
`dht.read11(pin)`
#### Parameters
`pin` 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 "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()](#dhtread)
## dht.readxx()
Read all kinds of DHT sensors, except DHT11.
####Syntax
`dht.readxx(pin)`
#### Parameters
`pin` 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 "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()](#dhtread)

View File

@ -0,0 +1,47 @@
# enduser setup Module
This module provides a simple way of configuring ESP8266 chips without using a serial interface or pre-programming WiFi credentials onto the chip.
![enduser setup config dialog](../../img/enduser-setup.jpg "enduser setup config dialog")
After running [`enduser_setup.start()`](#enduser_setupstart) a portal like the above can be accessed through a wireless network called SetupGadget_XXXXXX. The portal is used to submit the credentials for the WiFi of the enduser.
After an IP address has been successfully obtained this module will stop as if [`enduser_setup.stop()`](#enduser_setupstop) had been called.
## enduser_setup.start()
Starts the captive portal.
#### Syntax
`enduser_setup.start([onConfigured()], [onError(err_num, string)], [onDebug(string)])`
#### Parameters
- `onConfigured()` 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. It is intended to be used to find internal issues in the module. `string` contains a description of what is going on.
#### Returns
`nil`
#### Example
```lua
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.stop()
Stops the captive portal.
#### Syntax
`enduser_setup.stop()`
#### Parameters
none
#### Returns
`nil`

331
docs/en/modules/file.md Normal file
View File

@ -0,0 +1,331 @@
# file Module
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 directories/folders.
Only one file can be open at any given time.
## file.close()
Closes the open file, if any.
#### Syntax
`file.close()`
#### Parameters
none
#### Returns
`nil`
#### Example
```lua
-- open 'init.lua', print the first line.
file.open("init.lua", "r")
print(file.readline())
file.close()
```
#### See also
[`file.open()`](#fileopen)
## file.flush()
Flushes any pending writes to the file system, ensuring no data is lost on a restart. Closing the open file using [`file.close()`](#fileclose) performs an implicit flush as well.
#### Syntax
`file.flush()`
#### Parameters
none
#### Returns
`nil`
#### Example
```lua
-- open 'init.lua' in 'a+' mode
file.open("init.lua", "a+")
-- write 'foo bar' to the end of the file
file.write('foo bar')
file.flush()
-- write 'baz' too
file.write('baz')
file.close()
```
#### See also
[`file.close()`](#fileclose)
## 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.
#### Syntax
`file.format()`
#### Parameters
none
#### Returns
`nil`
#### See also
[`file.remove()`](#fileremove)
## file.fsinfo()
Return size information for the file system, in bytes.
#### Syntax
`file.fsinfo()`
#### Parameters
none
#### Returns
- `remaining` (number)
- `used` (number)
- `total` (number)
#### Example
```lua
-- get file system info
remaining, used, total=file.fsinfo()
print("\nFile system info:\nTotal : "..total.." Bytes\nUsed : "..used.." Bytes\nRemain: "..remaining.." Bytes\n")
```
## file.list()
Lists all files in the file system.
#### Syntax
`file.list()`
#### Parameters
none
#### Returns
a lua table which contains the {file name: file size} pairs
#### Example
```lua
l = file.list();
for k,v in pairs(l) do
print("name:"..k..", size:"..v)
end
```
## 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()`.
#### Syntax
`file.open(filename, mode)`
#### Parameters
- `filename` file to be opened, directories are not supported
- `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
`nil` if file not opened, or not exists (read modes). `true` if file opened ok.
#### Example
```lua
-- open 'init.lua', print the first line.
file.open("init.lua", "r")
print(file.readline())
file.close()
```
#### See also
- [`file.close()`](#fileclose)
- [`file.readline()`](#filereadline)
## file.read()
Read content from the open file.
#### Syntax
`file.read([n_or_str])`
#### Parameters
- `n_or_str`:
- if nothing passed in, read all byte in file
- if pass a number n, then read n bytes from file, or EOF is reached
- if pass a string "str", then read until 'str' or EOF is reached
#### Returns
fdile content in string, or nil when EOF
#### Example
```lua
-- print the first line of 'init.lua'
file.open("init.lua", "r")
print(file.read('\n'))
file.close()
-- print the first 5 byte of 'init.lua'
file.open("init.lua", "r")
print(file.read(5))
file.close()
```
#### See also
- [`file.open()`](#fileopen)
- [`file.readline()`](#filereadline)
## file.readline()
Read the next line from the open file.
#### Syntax
`file.readline()`
#### Parameters
none
#### Returns
File content in string, line by line, include EOL('\n'). Return `nil` when EOF.
#### Example
```lua
-- print the first line of 'init.lua'
file.open("init.lua", "r")
print(file.readline())
file.close()
```
#### See also
- [`file.open()`](#fileopen)
- [`file.close()`](#fileclose)
- [`file.read()`](#filereade)
## file.remove()
Remove a file from the file system. The file must not be currently open.
###Syntax
`file.remove(filename)`
#### Parameters
`filename` file to remove
#### Returns
`nil`
#### Example
```lua
-- remove "foo.lua" from file system.
file.remove("foo.lua")
```
#### See also
[`file.open()`](#fileopen)
## file.rename()
Renames a file. If a file is currently open, it will be closed first.
#### Syntax
`file.rename(oldname, newname)`
#### Parameters
- `oldname` old file name
- `newname` new file name
#### Returns
`true` on success, `false` on error.
#### Example
```lua
-- rename file 'temp.lua' to 'init.lua'.
file.rename("temp.lua","init.lua")
```
## file.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.
#### Syntax
`file.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
```lua
file.open("init.lua", "r")
-- skip the first 5 bytes of the file
file.seek("set", 5)
print(file.readline())
file.close()
```
#### See also
[`file.open()`](#fileopen)
## file.write()
Write a string to the open file.
#### Syntax
`file.write(string)`
#### Parameters
`string` content to be write to file
#### Returns
`true` if the write is ok, `nil` on error
#### Example
```lua
-- open 'init.lua' in 'a+' mode
file.open("init.lua", "a+")
-- write 'foo bar' to the end of the file
file.write('foo bar')
file.close()
```
#### See also
- [`file.open()`](#fileopen)
- [`file.writeline()`](#filewriteline)
## file.writeline()
Write a string to the open file and append '\n' at the end.
#### Syntax
`file.writeline(string)`
#### Parameters
`string` content to be write to file
#### Returns
`true` if write ok, `nil` on error
#### Example
```lua
-- open 'init.lua' in 'a+' mode
file.open("init.lua", "a+")
-- write 'foo bar' to the end of the file
file.writeline('foo bar')
file.close()
```
#### See also
- [`file.open()`](#fileopen)
- [`file.readline()`](#filereadline)

157
docs/en/modules/gpio.md Normal file
View File

@ -0,0 +1,157 @@
# GPIO Module
This module provides access to the [GPIO](https://en.wikipedia.org/wiki/General-purpose_input/output) (General Purpose Input/Output) subsystem.
All access is based on the I/O index number on the NodeMCU dev kits, not the internal GPIO pin. For example, the D0 pin on the dev kit is mapped to the internal GPIO pin 16.
If not using a NodeMCU dev kit, please refer to the below GPIO pin maps for the index↔gpio mapping.
| IO index | ESP8266 pin | IO index | ESP8266 pin |
|---------:|:------------|---------:|:------------|
| 0 [*] | GPIO16 | 7 | GPIO13 |
| 1 | GPIO5 | 8 | GPIO15 |
| 2 | GPIO4 | 9 | GPIO3 |
| 3 | GPIO0 | 10 | GPIO1 |
| 4 | GPIO2 | 11 | GPIO9 |
| 5 | GPIO14 | 12 | GPIO10 |
| 6 | GPIO12 | | |
** [*] D0(GPIO16) can only be used as gpio read/write. No interrupt support. No pwm/i2c/ow support. **
## gpio.mode()
Initialize pin to GPIO mode, set the pin in/out direction, and optional internal pullup.
#### Syntax
`gpio.mode(pin, mode [, pullup])`
#### Parameters
- `pin` pin to configure, IO index
- `mode` one of gpio.OUTPUT or gpio.INPUT, or gpio.INT(interrupt mode)
- `pullup` gpio.PULLUP or gpio.FLOAT; default is gpio.FLOAT
#### Returns
`nil`
#### Example
```lua
gpio.mode(0, gpio.OUTPUT)
```
#### See also
- [`gpio.read()`](#gpioread)
- [`gpio.write()`](#gpiowrite)
## gpio.read()
Read digital GPIO pin value.
#### Syntax
`gpio.read(pin)`
#### Parameters
`pin` pin to read, IO index
#### Returns
a number, 0 = low, 1 = high
#### Example
```lua
-- read value of gpio 0.
gpio.read(0)
```
#### See also
[`gpio.mode()`](#gpiomode)
## gpio.serout()
Serialize output based on a sequence of delay-times. After each delay, the pin is toggled.
#### Syntax
`gpio.serout(pin, start_level, delay_times [, repeat_num])`
#### Parameters
- `pin` pin to use, IO index
- `start_level` level to start on, either `gpio.HIGH` or `gpio.LOW`
- `delay_times` an array of delay times between each toggle of the gpio pin.
- `repeat_num` an optional number of times to run through the sequence.
Note that this function blocks, and as such any use of it must adhere to the SDK guidelines of time spent blocking the stack (10-100ms). Failure to do so may lead to WiFi issues or outright crashes/reboots.
#### Returns
`nil`
#### Example
```lua
gpio.mode(1,gpio.OUTPUT,gpio.PULLUP)
gpio.serout(1,1,{30,30,60,60,30,30}) -- serial one byte, b10110010
gpio.serout(1,1,{30,70},8) -- serial 30% pwm 10k, lasts 8 cycles
gpio.serout(1,1,{3,7},8) -- serial 30% pwm 100k, lasts 8 cycles
gpio.serout(1,1,{0,0},8) -- serial 50% pwm as fast as possible, lasts 8 cycles
gpio.serout(1,0,{20,10,10,20,10,10,10,100}) -- sim uart one byte 0x5A at about 100kbps
gpio.serout(1,1,{8,18},8) -- serial 30% pwm 38k, lasts 8 cycles
```
## gpio.trig()
Establish a callback function to run on interrupt for a pin.
There is currently no support for unregistering the callback.
This function is not available if GPIO_INTERRUPT_ENABLE was undefined at compile time.
#### Syntax
`gpio.trig(pin, type [, function(level)])`
#### Parameters
- `pin` **1~12**, IO index, pin D0 does not support interrupt.
- `type` "up", "down", "both", "low", "high", which represent rising edge, falling edge, both edge, low level, high level trig mode correspondingly.
- `function(level)` callback function when triggered. The gpio level is the param. Use previous callback function if undefined here.
#### Returns
`nil`
#### Example
```lua
-- use pin 1 as the input pulse width counter
pin = 1
pulse1 = 0
du = 0
gpio.mode(pin,gpio.INT)
function pin1cb(level)
du = tmr.now() - pulse1
print(du)
pulse1 = tmr.now()
if level == gpio.HIGH then gpio.trig(pin, "down") else gpio.trig(pin, "up") end
end
gpio.trig(pin, "down", pin1cb)
```
#### See also
[`gpio.mode()`](#gpiomode)
## gpio.write ()
Set digital GPIO pin value.
#### Syntax
`gpio.write(pin, level)`
#### Parameters
- `pin` pin to write, IO index
- `level` `gpio.HIGH` or `gpio.LOW`
#### Returns
`nil`
#### Example
```lua
-- set pin index 1 to GPIO mode, and set the pin to high.
pin=1
gpio.mode(pin, gpio.OUTPUT)
gpio.write(pin, gpio.HIGH)
```
#### See also
- [`gpio.mode()`](#gpiomode)
- [`gpio.read()`](#gpioread)

165
docs/en/modules/http.md Normal file
View File

@ -0,0 +1,165 @@
# HTTP Module
Basic HTTP client module.
Provides an interface to do basic GET/POST/PUT/DELETE over HTTP(S), as well as customized requests. Due to the memory constraints on ESP8266, the supported page/body size is limited to 1k. Attempting to receive pages larger than this limit will fail. If larger page/body sizes are necessary, consider using `net.createConnection()` and stream in the data.
Each request method takes a callback which is invoked when the response has been received from the server. The first argument is the status code, which is either a regular HTTP status code, or -1 to denote a DNS, connection or out-of-memory failure, or a timeout (currently at 10 seconds).
For each operation it is also possible to include custom headers. Note that following headers *can not* be overridden however:
- Host
- Connection
- User-Agent
The `Host` header is taken from the URL itself, the `Connection` is always set to `close`, and the `User-Agent` is `ESP8266`.
Note that it is not possible to execute concurrent HTTP requests using this module. Starting a new request before the previous has completed will result in undefined behaviour.
#### See also
- [`net.createConnection()`](#netcreateconnection)
## http.delete()
Executes a HTTP delete request.
#### Syntax
`http.delete(url, headers, body, callback)`
#### Parameters
- `url` The URL to fetch, including the `http://` or `https://` prefix
- `headers` Optional additional headers to append, *including \r\n*; may be `nil`
- `body` The body to post; must already be encoded in the appropriate format, but may be empty
- `callback` The callback function to be invoked when the response has been received; it is invoked with the arguments `status_code` and `body`
#### Returns
`nil`
#### Example
```lua
http.delete('https://connor.example.com/john',
"",
"",
function(code, data)
if (code < 0)
print("HTTP request failed")
else
print(code, data)
end
end)
```
## http.get()
Executes a HTTP GET request.
#### Syntax
`http.get(url, headers, callback)`
#### Parameters
- `url` The URL to fetch, including the `http://` or `https://` prefix
- `headers` Optional additional headers to append, *including \r\n*; may be `nil`
- `callback` The callback function to be invoked when the response has been received; it is invoked with the arguments `status_code` and `body`
#### Returns
`nil`
#### Example
```lua
http.get("https://www.vowstar.com/nodemcu/", nil, function(code, data)
if (code < 0)
print("HTTP request failed")
else
print(code, data)
end
end)
```
## http.post()
Executes a HTTP POST request.
#### Syntax
`http.post(url, headers, body, callback)`
#### Parameters
- `url` The URL to fetch, including the `http://` or `https://` prefix
- `headers` Optional additional headers to append, *including \r\n*; may be `nil`
- `body` The body to post; must already be encoded in the appropriate format, but may be empty
- `callback` The callback function to be invoked when the response has been received; it is invoked with the arguments `status_code` and `body`
#### Returns
`nil`
#### Example
```lua
http.post('http://json.example.com/something',
'Content-Type: application/json\r\n',
'{"hello":"world"}',
function(code, data)
if (code < 0)
print("HTTP request failed")
else
print(code, data)
end
end)
```
## http.put()
Executes a HTTP PUT request.
#### Syntax
`http.put(url, headers, body, callback)`
#### Parameters
- `url` The URL to fetch, including the `http://` or `https://` prefix
- `headers` Optional additional headers to append, *including \r\n*; may be `nil`
- `body` The body to post; must already be encoded in the appropriate format, but may be empty
- `callback` The callback function to be invoked when the response has been received; it is invoked with the arguments `status_code` and `body`
#### Returns
`nil`
#### Example
```lua
http.put('http://db.example.com/items.php?key=deckard',
'Content-Type: text/plain\r\n',
'Hello!\nStay a while, and listen...\n',
function(code, data)
if (code < 0)
print("HTTP request failed")
else
print(code, data)
end
end)
```
## http.request()
Execute a custom HTTP request for any HTTP method.
#### Syntax
`http.request(url, method, headers, body, callback)`
#### Parameters
- `url` The URL to fetch, including the `http://` or `https://` prefix
- `method` The HTTP method to use, e.g. "GET", "HEAD", "OPTIONS" etc
- `headers` Optional additional headers to append, *including \r\n*; may be `nil`
- `body` The body to post; must already be encoded in the appropriate format, but may be empty
- `callback` The callback function to be invoked when the response has been received; it is invoked with the arguments `status_code` and `body`
#### Returns
`nil`
#### Example
```lua
http.request("https://www.example.com", "HEAD", "", "", function(code, data)
function(code, data)
if (code < 0)
print("HTTP request failed")
else
print(code, data)
end
end)
```

48
docs/en/modules/hx711.md Normal file
View File

@ -0,0 +1,48 @@
# HX711 Module
This module provides access to an [HX711 load cell amplifier/ADC](https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide). The HX711 is an inexpensive 24bit ADC with programmable 128x, 64x, and 32x gain. Currently only channel A at 128x gain is supported.
Note: To save ROM image space, this module is not compiled into the firmware by default.
## hx711.init()
Initialize io pins for hx711 clock and data.
#### Syntax
`hx711.init(clk, data)`
#### Parameters
- `clk` pin the hx711 clock signal is connected to
- `data` pin the hx711 data signal is connected to
#### Returns
`nil`
#### Example
```lua
-- Initialize the hx711 with clk on pin 5 and data on pin 6
hx711.init(5,6)
```
## hx711.read()
Read digital loadcell ADC value.
#### Syntax
`hx711.read(mode)`
#### Parameters
`mode` ADC mode. This parameter is currently ignored and reserved to ensure backward compatability if support for additional modes is added. Currently only channel A @ 128 gain is supported.
|mode | channel | gain |
|-----|---------|------|
| 0 | A | 128 |
#### Returns
a number (24 bit signed ADC value extended to the machine int size)
#### Example
```lua
-- Read ch A with 128 gain.
raw_data = hx711.read(0)
```

130
docs/en/modules/i2c.md Normal file
View File

@ -0,0 +1,130 @@
# i2c Module
## i2c.address()
Setup I²C address and read/write mode for the next transfer.
#### Syntax
`i2c.address(id, device_addr, direction)`
#### Parameters
- `id` always 0
- `device_addr` device address
- `direction` `i2c.TRANSMITTER` for writing mode , `i2c. RECEIVER` for reading mode
#### Returns
`true` if ack received, `false` if no ack received.
#### See also
[i2c.read()](#i2cread)
## i2c.read()
Read data for variable number of bytes.
#### Syntax
`i2c.read(id, len)`
#### Parameters
- `id` always 0
- `len` number of data bytes
#### Returns
`string` of received data
#### Example
```lua
id = 0
sda = 1
scl = 2
-- initialize i2c, set pin1 as sda, set pin2 as scl
i2c.setup(id, sda, scl, i2c.SLOW)
-- user defined function: read from reg_addr content of dev_addr
function read_reg(dev_addr, reg_addr)
i2c.start(id)
i2c.address(id, dev_addr, i2c.TRANSMITTER)
i2c.write(id, reg_addr)
i2c.stop(id)
i2c.start(id)
i2c.address(id, dev_addr, i2c.RECEIVER)
c = i2c.read(id, 1)
i2c.stop(id)
return c
end
-- get content of register 0xAA of device 0x77
reg = read_reg(0x77, 0xAA)
print(string.byte(reg))
```
####See also
[i2c.write()](#i2cwrite)
## i2c.setup()
Initialize the I²C module.
#### Syntax
`i2c.setup(id, pinSDA, pinSCL, speed)`
####Parameters
- `id` always 0
- `pinSDA` 1~12, IO index
- `pinSCL` 1~12, IO index
- `speed` only `i2c.SLOW` supported
#### Returns
`speed` the selected speed
####See also
[i2c.read()](#i2cread)
## i2c.start()
Send an I²C start condition.
#### Syntax
`i2c.start(id)`
#### Parameters
`id` always 0
#### Returns
`nil`
####See also
[i2c.read()](#i2cread)
## i2c.stop()
Send an I²C stop condition.
#### Syntax
`i2c.stop(id)`
####Parameters
`id` always 0
#### Returns
`nil`
####See also
[i2c.read()](#i2cread)
## i2c.write()
Write data to I²C bus. Data items can be multiple numbers, strings or lua tables.
####Syntax
`i2c.write(id, data1[, data2[, ..., datan]])`
####Parameters
- `id` always 0
- `data` data can be numbers, string or lua table.
#### Returns
`number` number of bytes written
#### Example
```lua
i2c.write(0, "hello", "world")
```
#### See also
[i2c.read()](#i2cread)

152
docs/en/modules/mqtt.md Normal file
View File

@ -0,0 +1,152 @@
# MQTT Module
The client adheres to version 3.1.1 of the [MQTT](https://en.wikipedia.org/wiki/MQTT) protocol. Make sure that your broker supports and is correctly configured for version 3.1.1. The client is backwards incompatible with brokers running MQTT 3.1.
## mqtt.Client()
Creates a MQTT client.
#### Syntax
`mqtt.Client(clientid, keepalive, username, password[, cleansession])`
#### Parameters
- `clientid` client ID
- `keepalive` keepalive seconds
- `username` user name
- `password` user password
- `cleansession` 0/1 for `false`/`true`
#### Returns
MQTT client
#### Example
```lua
-- init mqtt client with keepalive timer 120sec
m = mqtt.Client("clientid", 120, "user", "password")
-- setup Last Will and Testament (optional)
-- Broker will publish a message with qos = 0, retain = 0, data = "offline"
-- to topic "/lwt" if client don't send keepalive packet
m:lwt("/lwt", "offline", 0, 0)
m:on("connect", function(client) print ("connected") end)
m:on("offline", function(client) print ("offline") end)
-- on publish message receive event
m:on("message", function(client, topic, data)
print(topic .. ":" )
if data ~= nil then
print(data)
end
end)
-- for TLS: m:connect("192.168.11.118", secure-port, 1)
m:connect("192.168.11.118", 1880, 0, function(client) print("connected") end)
-- Calling subscribe/publish only makes sense once the connection
-- was successfully established. In a real-world application you want
-- move those into the 'connect' callback or make otherwise sure the
-- connection was established.
-- subscribe topic with qos = 0
m:subscribe("/topic",0, function(client) print("subscribe success") end)
-- publish a message with data = hello, QoS = 0, retain = 0
m:publish("/topic","hello",0,0, function(client) print("sent") end)
m:close();
-- you can call m:connect again
```
# MQTT Client
## mqtt.client:close()
Closes connection to the broker.
#### Syntax
`mqtt:close()`
#### Parameters
none
#### Returns
`nil`
## mqtt.client:connect()
Connects to the broker specified by the given host, port, and secure options.
#### Syntax
`mqtt:connect(host, port, secure, function(client))`
#### Parameters
- `host` host, domain or IP (string)
- `port` broker port (number)
- `secure` 0/1 for `false`/`true`, default 0. [As per #539](https://github.com/nodemcu/nodemcu-firmware/issues/539#issuecomment-170298120) secure connections use TLS 1.2.
- `function(client)` call back function for when the connection was established
#### Returns
`nil`
## mqtt.client:lwt()
Setup [Last Will and Testament](http://www.hivemq.com/blog/mqtt-essentials-part-9-last-will-and-testament) (optional). A broker will publish a message with qos = 0, retain = 0, data = "offline" to topic "/lwt" if client does not send keepalive packet.
#### Syntax
`mqtt:lwt(topic, message, qos, retain)`
#### Parameters
- `topic` the topic to publish to (string)
- `message` the message to publish, (buffer or string)
- `qos` QoS level, default 0
- `retain` retain flag, default 0
#### Returns
`nil`
## mqtt.client:on()
Registers a callback function for an event.
#### Syntax
`mqtt:on(event, function(client[, topic[, message]]))`
#### Parameters
- `event` can be "connect", "message" or "offline"
- `function(client[, topic[, message]])` callback function. The first parameter is the client. If event is "message", the 2nd and 3rd param are received topic and message (strings).
#### Returns
`nil`
## mqtt.client:publish()
Publishes a message.
#### Syntax
`mqtt:publish(topic, payload, qos, retain, function(client))`
#### Parameters
- `topic` the topic to publish to ([topic string](http://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics-best-practices))
- `message` the message to publish, (buffer or string)
- `qos` QoS level, default 0
- `retain` retain flag, default 0
- `function(client)` callback fired when PUBACK received
#### Returns
`nil`
## mqtt.client:subscribe()
Subscribes to one or several topics.
#### Syntax
`mqtt:subscribe(topic, qos, function(client, topic, message))`
#### Parameters
- `topic` a [topic string](http://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics-best-practices)
- `qos` QoS subscription level, default 0
- `function(client, topic, message)` callback fired when message received
#### Returns
`nil`

284
docs/en/modules/net.md Normal file
View File

@ -0,0 +1,284 @@
# net Module
## Constants
`net.TCP`, `net.UDP`
## net.createConnection()
Creates a client.
#### Syntax
`net.createConnection(type, secure)`
#### Parameters
- `type` `net.TCP` or `net.UDP`
- `secure` 1 for encrypted, 0 for plain
#### Returns
net.socket sub module
#### Example
```lua
net.createConnection(net.UDP, 0)
```
#### See also
[`net.createServer()`](#netcreateserver)
## net.createServer()
Creates a server.
#### Syntax
`net.createServer(type, timeout)`
#### Parameters
- `type` `net.TCP` or `net.UDP`
- `timeout` for a TCP server timeout is 1~28'800 seconds (for an inactive client to be disconnected)
#### Returns
net.server sub module
#### Example
```lua
net.createServer(net.TCP, 30) -- 30s timeout
```
#### See also
[`net.createConnection()`](#netcreateconnection)
# net.server Module
## net.server:close()
Closes the server.
#### Syntax
`net.server.close()`
#### Parameters
none
#### Returns
`nil`
#### Example
```lua
-- creates a server
sv = net.createServer(net.TCP, 30)
-- closes the server
sv:close()
```
#### See also
[`net.createServer()`](#netcreateserver)
## net.server:listen()
Listen on port from IP address.
#### Syntax
`net.server.listen(port,[ip],function(net.socket))`
#### Parameters
- `port` port number
- `ip` IP address string, can be omitted
- `function(net.socket)` callback function, pass to caller function as param if a connection is created successfully
#### Returns
`nil`
#### Example
```lua
-- 30s time out for a inactive client
sv = net.createServer(net.TCP, 30)
-- server listens on 80, if data received, print data to console and send "hello world" back to caller
sv:listen(80, function(c)
c:on("receive", function(c, pl)
print(pl)
end)
c:send("hello world")
end)
```
#### See also
[`net.createServer()`](#netcreateserver)
# net.socket Module
## net.socket:close()
Closes socket.
#### Syntax
`close()`
#### Parameters
none
#### Returns
`nil`
#### See also
[`net.createServer()`](#netcreateserver)
## net.socket:connect()
Connect to a remote server.
#### Syntax
`connect(port, ip|domain)`
#### Parameters
- `port` port number
- `ip` IP address or domain name string
#### Returns
`nil`
#### See also
[`net.socket:on()`](#netsocketon)
## net.socket:dns()
Provides DNS resolution for a hostname.
#### Syntax
`dns(domain, function(net.socket, ip))`
#### Parameters
- `domain` domain name
- `function(net.socket, ip)` callback function. The first parameter is the socket, the second parameter is the IP address as a string.
#### Returns
`nil`
#### Example
```lua
sk = net.createConnection(net.TCP, 0)
sk:dns("www.nodemcu.com", function(conn, ip) print(ip) end)
sk = nil
```
#### See also
[`net.createServer()`](#netcreateserver)
## net.socket:on()
Register callback functions for specific events.
#### Syntax
`on(event, function())`
#### Parameters
- `event` string, which can be "connection", "reconnection", "disconnection", "receive" or "sent"
- `function(net.socket[, string])` callback function. The first parameter is the socket. If event is "receive", the second parameter is the received data as string.
#### Returns
`nil`
#### Example
```lua
sk = net.createConnection(net.TCP, 0)
sk:on("receive", function(sck, c) print(c) end )
sk:connect(80,"192.168.0.66")
sk:on("connection", function(sck,c)
-- Wait for connection before sending.
sk:send("GET / HTTP/1.1\r\nHost: 192.168.0.66\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n")
end)
```
#### See also
[`net.createServer()`](#netcreateserver)
## net.socket:send()
Sends data to server.
#### Syntax
`send(string, function(sent))`
#### Parameters
- `string` data in string which will be sent to server
- `function(sent)` callback function for sending string
#### Returns
`nil`
#### Note
Multiple consecutive `send()` calls aren't guaranteed to work (and often don't) as network requests are treated as separate tasks by the SDK. Instead, subscribe to the "sent" event on the socket and send additional data (or close) in that callback. See [#730](https://github.com/nodemcu/nodemcu-firmware/issues/730#issuecomment-154241161) for an example and explanation.
#### See also
[`net.socket:on()`](#netsocketon)
# net.dns Module
## net.dns.getdnsserver()
Gets the IP address of the DNS server used to resolve hostnames.
#### Syntax
`net.dns.getdnsserver(dns_index)`
#### Parameters
dns_index which DNS server to get (range 0~1)
#### Returns
IP address (string) of DNS server
#### Example
```lua
print(net.dns.getdnsserver(0)) -- 208.67.222.222
print(net.dns.getdnsserver(1)) -- nil
net.dns.setdnsserver("8.8.8.8", 0)
net.dns.setdnsserver("192.168.1.252", 1)
print(net.dns.getdnsserver(0)) -- 8.8.8.8
print(net.dns.getdnsserver(1)) -- 192.168.1.252
```
#### See also
[`net.dns:setdnsserver()`](#netdnssetdnsserver)
## net.dns.resolve()
Resolve a hostname to an IP address. Doesn't require a socket like [`net.socket.dns()`](#netsocketdns).
#### Syntax
`net.dns.resolve(host, function(ip))`
#### Parameters
- `host` hostname to resolve
- `function(sk, ip)` callback called when the name was resolved. Don't use `sk`, it's a socket used internally to resolve the hostname.
#### Returns
`nil`
#### Example
```lua
net.dns.resolve("www.google.com", function(sk, ip)
if (ip == nil) then print("DNS fail!") else print(ip) end
end)
```
#### See also
[`net.socket:dns()`](#netsocketdns)
## net.dns.setdnsserver()
Sets the IP of the DNS server used to resolve hostnames. Default: resolver1.opendns.com (208.67.222.222). You can specify up to 2 DNS servers.
#### Syntax
`net.dns.setdnsserver(dns_ip_addr, dns_index)`
#### Parameters
- `dns_ip_addr` IP address of a DNS server
- `dns_index` which DNS server to set (range 0~1). Hence, it supports max. 2 servers.
#### Returns
`nil`
#### See also
[`net.dns:getdnsserver()`](#netdnsgetdnsserver)

380
docs/en/modules/node.md Normal file
View File

@ -0,0 +1,380 @@
# node Module
The node module provides access to system-level features such as sleep, restart and various info and IDs.
## node.bootreason()
Returns the boot reason and extended reset info.
The first value returned is the raw code, not the new "reset info" code which was introduced in recent SDKs. Values are:
- 1, power-on
- 2, reset (software?)
- 3, hardware reset via reset pin
- 4, WDT reset (watchdog timeout)
The second value returned is the extended reset cause. Values are:
- 0, power-on
- 1, hardware watchdog reset
- 2, exception reset
- 3, software watchdog reset
- 4, software restart
- 5, wake from deep sleep
- 6, external reset
In general, the extended reset cause supercedes the raw code. The raw code is kept for backwards compatibility only. For new applications it is highly recommended to use the extended reset cause instead.
In case of extended reset cause 3 (exception reset), additional values are returned containing the crash information. These are, in order, EXCCAUSE, EPC1, EPC2, EPC3, EXCVADDR, and DEPC.
#### Syntax
`node.bootreason()`
#### Parameters
none
#### Returns
`rawcode, reason [, exccause, epc1, epc2, epc3, excvaddr, depc ]`
#### Example
```lua
_, reset_reason = node.bootreason()
if reset_reason == 0 then print("Power UP!") end
```
## node.chipid()
Returns the ESP chip ID.
#### Syntax
`node.chipid()`
#### Parameters
none
#### Returns
chip ID (number)
## node.compile()
Compiles a Lua text file into Lua bytecode, and saves it as .lc file.
#### Syntax
`node.compile("file.lua")`
#### Parameters
`filename` name of Lua text file
#### Returns
`nil`
#### Example
```lua
file.open("hello.lua","w+")
file.writeline([[print("hello nodemcu")]])
file.writeline([[print(node.heap())]])
file.close()
node.compile("hello.lua")
dofile("hello.lua")
dofile("hello.lc")
```
## node.dsleep()
Enters deep sleep mode, wakes up when timed out.
The maximum sleep time is 4294967295us, ~71 minutes. This is an SDK limitation.
Firmware from before 05 Jan 2016 have a maximum sleeptime of ~35 minutes.
!!! note "Note:"
This function can only be used in the condition that esp8266 PIN32(RST) and PIN8(XPD_DCDC aka GPIO16) are connected together. Using sleep(0) will set no wake up timer, connect a GPIO to pin RST, the chip will wake up by a falling-edge on pin RST.
#### Syntax
`node.dsleep(us, option)`
#### Parameters
- `us` number (integer) or `nil`, sleep time in micro second. If `us == 0`, it will sleep forever. If `us == nil`, will not set sleep time.
- `option` number (integer) or `nil`. If `nil`, it will use last alive setting as default option.
- 0, init data byte 108 is valuable
- \> 0, init data byte 108 is valueless
- 0, RF_CAL or not after deep-sleep wake up, depends on init data byte 108
- 1, RF_CAL after deep-sleep wake up, there will belarge current
- 2, no RF_CAL after deep-sleep wake up, there will only be small current
- 4, disable RF after deep-sleep wake up, just like modem sleep, there will be the smallest current
#### Returns
`nil`
#### Example
```lua
--do nothing
node.dsleep()
--sleep μs
node.dsleep(1000000)
--set sleep option, then sleep μs
node.dsleep(1000000, 4)
--set sleep option only
node.dsleep(nil,4)
```
## node.flashid()
Returns the flash chip ID.
#### Syntax
`node.flashid()`
#### Parameters
none
#### Returns
flash ID (number)
## node.heap()
Returns the current available heap size in bytes. Note that due to fragmentation, actual allocations of this size may not be possible.
#### Syntax
`node.heap()`
#### Parameters
none
#### Returns
system heap size left in bytes (number)
## node.info()
Returns NodeMCU version, chipid, flashid, flash size, flash mode, flash speed.
#### Syntax
`node.info()`
#### Parameters
none
#### Returns
- `majorVer` (number)
- `minorVer` (number)
- `devVer` (number)
- `chipid` (number)
- `flashid` (number)
- `flashsize` (number)
- `flashmode` (number)
- `flashspeed` (number)
#### Example
```lua
majorVer, minorVer, devVer, chipid, flashid, flashsize, flashmode, flashspeed = node.info()
print("NodeMCU "..majorVer.."."..minorVer.."."..devVer)
```
## node.input()
Submits a string to the Lua interpreter. Similar to `pcall(loadstring(str))`, but without the single-line limitation.
!!! note "Note:"
This function only has an effect when invoked from a callback. Using it directly on the console **does not work**.
#### Syntax
`node.input(str)`
#### Parameters
`str` Lua chunk
#### Returns
`nil`
#### Example
```lua
sk:on("receive", function(conn, payload) node.input(payload) end)
```
#### See also
[`node.output()`](#nodeoutput)
## node.key() --deprecated
Defines action to take on button press (on the old devkit 0.9), button connected to GPIO 16.
This function is only available if the firmware was compiled with DEVKIT_VERSION_0_9 defined.
#### Syntax
`node.key(type, function())`
#### Parameters
- `type`: type is either string "long" or "short". long: press the key for 3 seconds, short: press shortly(less than 3 seconds)
- `function`: user defined function which is called when key is pressed. If nil, remove the user defined function. Default function: long: change LED blinking rate, short: reset chip
#### Returns
`nil`
#### Example
```lua
node.key("long", function() print('hello world') end)
```
#### See also
[`node.led()`](#nodeled-deprecated)
## node.led() --deprecated
Sets the on/off time for the LED (on the old devkit 0.9), with the LED connected to GPIO16, multiplexed with [`node.key()`](#nodekey-deprecated).
This function is only available if the firmware was compiled with DEVKIT_VERSION_0_9 defined.
#### Syntax
`node.led(low, high)`
#### Parameters
- `low` LED off time, LED keeps on when low=0. Unit: milliseconds, time resolution: 80~100ms
- `high` LED on time. Unit: milliseconds, time resolution: 80~100ms
#### Returns
`nil`
#### Example
```lua
-- turn led on forever.
node.led(0)
```
#### See also
[`node.key()`](#nodekey-deprecated)
## node.output()
Redirects the Lua interpreter output to a callback function. Optionally also prints it to the serial console.
!!! note "Note:"
Do **not** attempt to `print()` or otherwise induce the Lua interpreter to produce output from within the callback function. Doing so results in infinite recursion, and leads to a watchdog-triggered restart.
#### Syntax
`node.output(function(str), serial_debug)`
#### Parameters
- `output_fn(str)` a function accept every output as str, and can send the output to a socket (or maybe a file).
- `serial_debug` 1 output also show in serial. 0: no serial output.
#### Returns
`nil`
#### Example
```lua
function tonet(str)
sk:send(str)
end
node.output(tonet, 1) -- serial also get the lua output.
```
```lua
-- a simple telnet server
s=net.createServer(net.TCP)
s:listen(2323,function(c)
con_std = c
function s_output(str)
if(con_std~=nil)
then con_std:send(str)
end
end
node.output(s_output, 0) -- re-direct output to function s_ouput.
c:on("receive",function(c,l)
node.input(l) -- works like pcall(loadstring(l)) but support multiple separate line
end)
c:on("disconnection",function(c)
con_std = nil
node.output(nil) -- un-regist the redirect output function, output goes to serial
end)
end)
```
#### See also
[`node.input()`](#nodeinput)
## node.readvdd33() --deprecated
Moved to [`adc.readvdd33()`](adc/#adcreadvdd33).
## node.restart()
Restarts the chip.
#### Syntax
`node.restart()`
#### Parameters
none
#### Returns
`nil`
## node.restore()
Restores system configuration to defaults. Erases all stored WiFi settings, and resets the "esp init data" to the defaults. This function is intended as a last-resort without having to reflash the ESP altogether.
This also uses the SDK function `system_restore()`, which doesn't document precisely what it erases/restores.
#### Syntax
`node.restore()`
#### Parameters
none
#### Returns
`nil`
#### Example
```lua
node.restore()
node.restart() -- ensure the restored settings take effect
```
## node.setcpufreq()
Change the working CPU Frequency.
#### Syntax
`node.setcpufreq(speed)`
#### Parameters
`speed` constant 'node.CPU80MHZ' or 'node.CPU160MHZ'
#### Returns
target CPU frequency (number)
#### Example
```lua
node.setcpufreq(node.CPU80MHZ)
```
## node.stripdebug()
Controls the amount of debug information kept during [`node.compile()`](#nodecompile), and allows removal of debug information from already compiled Lua code.
Only recommended for advanced users, the NodeMCU defaults are fine for almost all use cases.
####Syntax
`node.stripdebug([level[, function]])`
#### Parameters
- `level`
- 1, don't discard debug info
- 2, discard Local and Upvalue debug info
- 3, discard Local, Upvalue and line-number debug info
- `function` a compiled function to be stripped per setfenv except 0 is not permitted.
If no arguments are given then the current default setting is returned. If function is omitted, this is the default setting for future compiles. The function argument uses the same rules as for `setfenv()`.
#### Returns
If invoked without arguments, returns the current level settings. Otherwise, `nil` is returned.
#### Example
```lua
node.stripdebug(3)
node.compile('bigstuff.lua')
```
#### See also
[`node.compile()`](#nodecompile)

271
docs/en/modules/ow.md Normal file
View File

@ -0,0 +1,271 @@
# 1-Wire Module
This module provides functions to work with the [1-Wire](https://en.wikipedia.org/wiki/1-Wire) device communications bus system.
## ow.check_crc16()
Computes the 1-Wire CRC16 and compare it against the received CRC.
#### Syntax
`ow.check_crc16(buf, inverted_crc0, inverted_crc1[, crc])`
#### Parameters
- `buf` string value, data to be calculated check sum in string
- `inverted_crc0` LSB of received CRC
- `inverted_crc1` MSB of received CRC
- `crc` CRC starting value (optional)
#### Returns
true if the CRC matches, false otherwise
## ow.crc16()
Computes a Dallas Semiconductor 16 bit CRC. This is required to check the integrity of data received from many 1-Wire devices. Note that the CRC computed here is **not** what you'll get from the 1-Wire network, for two reasons:
1. The CRC is transmitted bitwise inverted.
2. Depending on the endian-ness of your processor, the binary representation of the two-byte return value may have a different byte order than the two bytes you get from 1-Wire.
#### Syntax
`ow.crc16(buf[, crc])`
#### Parameters
- `buf` string value, data to be calculated check sum in string
- `crc` CRC starting value (optional)
#### Returns
the CRC16 as defined by Dallas Semiconductor
## ow.crc8()
Computes a Dallas Semiconductor 8 bit CRC, these are used in the ROM and scratchpad registers.
#### Syntax
`ow.crc8(buf)`
#### Parameters
`buf` string value, data to be calculated check sum in string
#### Returns
CRC result as byte
## ow.depower()
Stops forcing power onto the bus. You only need to do this if you used the 'power' flag to `ow.write()` or used a `ow.write_bytes()` and aren't about to do another read or write.
#### Syntax
`ow.depower(pin)`
#### Parameters
`pin` 1~12, I/O index
#### Returns
`nil`
####See also
- [ow.write()](#owwrite)
- [ow.write_bytes()](#owwrite_bytes)
## ow.read()
Reads a byte.
####Syntax
`ow.read(pin)`
#### Parameters
`pin` 1~12, I/O index
#### Returns
byte read from slave device
## ow.read_bytes()
Reads multi bytes.
#### Syntax
`ow.read_bytes(pin, size)`
#### Parameters
- `pin` 1~12, I/O index
- `size` number of bytes to be read from slave device
#### Returns
`string` bytes read from slave device
## ow.reset()
Performs a 1-Wire reset cycle.
#### Syntax
`ow.reset(pin)`
#### Parameters
`pin` 1~12, I/O index
#### Returns
- `1` if a device responds with a presence pulse
- `0` if there is no device or the bus is shorted or otherwise held low for more than 250 µS
## ow.reset_search()
Clears the search state so that it will start from the beginning again.
#### Syntax
`ow.reset_search(pin)`
#### Parameters
`pin` 1~12, I/O index
#### Returns
`nil`
## ow.search()
Looks for the next device.
#### Syntax
`ow.search(pin)`
#### Parameters
`pin` 1~12, I/O index
#### Returns
`rom_code` string with length of 8 upon success. It contains the rom code of slave device. Returns `nil` if search was unsuccessful.
#### See also
[ow.target_search()](#owtargetsearch)
## ow.select()
Issues a 1-Wire rom select command. Make sure you do the `ow.reset(pin)` first.
#### Syntax
`ow.select(pin, rom)`
#### Parameters
- `pin` 1~12, I/O index
- `rom` string value, len 8, rom code of the salve device
#### Returns
`nil`
#### Example
```lua
-- 18b20 Example
pin = 9
ow.setup(pin)
count = 0
repeat
count = count + 1
addr = ow.reset_search(pin)
addr = ow.search(pin)
tmr.wdclr()
until (addr ~= nil) or (count > 100)
if addr == nil then
print("No more addresses.")
else
print(addr:byte(1,8))
crc = ow.crc8(string.sub(addr,1,7))
if crc == addr:byte(8) then
if (addr:byte(1) == 0x10) or (addr:byte(1) == 0x28) then
print("Device is a DS18S20 family device.")
repeat
ow.reset(pin)
ow.select(pin, addr)
ow.write(pin, 0x44, 1)
tmr.delay(1000000)
present = ow.reset(pin)
ow.select(pin, addr)
ow.write(pin,0xBE,1)
print("P="..present)
data = nil
data = string.char(ow.read(pin))
for i = 1, 8 do
data = data .. string.char(ow.read(pin))
end
print(data:byte(1,9))
crc = ow.crc8(string.sub(data,1,8))
print("CRC="..crc)
if crc == data:byte(9) then
t = (data:byte(1) + data:byte(2) * 256) * 625
t1 = t / 10000
t2 = t % 10000
print("Temperature="..t1.."."..t2.."Centigrade")
end
tmr.wdclr()
until false
else
print("Device family is not recognized.")
end
else
print("CRC is not valid!")
end
end
```
####See also
[ow.reset()](#owreset)
## ow.setup()
Sets a pin in onewire mode.
#### Syntax
`ow.setup(pin)`
#### Parameters
`pin` 1~12, I/O index
#### Returns
`nil`
## ow.skip()
Issues a 1-Wire rom skip command, to address all on bus.
#### Syntax
`ow.skip(pin)`
#### Parameters
`pin` 1~12, I/O index
#### Returns
`nil`
## ow.target_search()
Sets up the search to find the device type `family_code`. The search itself has to be initiated with a subsequent call to `ow.search()`.
#### Syntax
`ow.target_search(pin, family_code)`
#### Parameters
- `pin` 1~12, I/O index
- `family_code` byte for family code
#### Returns
`nil`
####See also
[ow.search()](#owsearch)
## ow.write()
Writes a byte. If `power` is 1 then the wire is held high at the end for parasitically powered devices. You are responsible for eventually depowering it by calling `ow.depower()` or doing another read or write.
#### Syntax
`ow.write(pin, v, power)`
#### Parameters
- `pin` 1~12, I/O index
- `v` byte to be written to salve device
- `power` 1 for wire being held high for parasitically powered devices
#### Returns
`nil`
####See also
[ow.depower()](#owdepower)
## ow.write_bytes()
Writes multi bytes. If `power` is 1 then the wire is held high at the end for parasitically powered devices. You are responsible for eventually depowering it by calling `ow.depower()` or doing another read or write.
#### Syntax
`ow.write_bytes(pin, buf, power)`
#### Parameters
- `pin` 1~12, IO index
- `buf` string to be written to slave device
- `power` 1 for wire being held high for parasitically powered devices
#### Returns
`nil`
####See also
[ow.depower()](#owdepower)

152
docs/en/modules/pwm.md Normal file
View File

@ -0,0 +1,152 @@
# pwm Module
## pwm.close()
Quit PWM mode for the specified GPIO pin.
#### Syntax
`pwm.close(pin)`
#### Parameters
`pin` 1~12, IO index
#### Returns
`nil`
#### See also
[pwm.start()](#pwmstart)
## pwm.getclock()
Get selected PWM frequency of pin.
#### Syntax
`pwm.getclock(pin)`
#### Parameters
`pin` 1~12, IO index
#### Returns
`number` PWM frequency of pin
#### See also
[pwm.setclock()](#pwmsetclock)
#### See also
[pwm.getduty()](#pwmgetduty)
## pwm.getduty()
Get selected duty cycle of pin.
#### Syntax
`pwm.getduty(pin)`
#### Parameters
`pin` 1~12, IO index
#### Returns
`number` duty cycle, max 1023
#### See also
[pwm.setduty()](#pwmsetduty)
## pwm.setclock()
Set PWM frequency.
**Note:** Setup of the PWM frequency will synchronously change other setups as well if there are any. Only one PWM frequency can be allowed for the system.
#### Syntax
`pwm.setclock(pin, clock)`
#### Parameters
- `pin` 1~12, IO index
- `clock` 1~1000, PWM frequency
#### Returns
`nil`
#### See also
[pwm.getclock()](#pwmgetclock)
## pwm.setduty()
Set duty cycle for a pin.
#### Syntax
`pwm.setduty(pin, duty)`
#### Parameters
- `pin` 1~12, IO index
- `duty` 0~1023, pwm duty cycle, max 1023 (10bit)
#### Returns
`nil`
#### Example
```lua
-- D1 is connected to green led
-- D2 is connected to blue led
-- D3 is connected to red led
pwm.setup(1, 500, 512)
pwm.setup(2, 500, 512)
pwm.setup(3, 500, 512)
pwm.start(1)
pwm.start(2)
pwm.start(3)
function led(r, g, b)
pwm.setduty(1, g)
pwm.setduty(2, b)
pwm.setduty(3, r)
end
led(512, 0, 0) -- set led to red
led(0, 0, 512) -- set led to blue.
```
## pwm.setup()
Set pin to PWM mode. Only 6 pins can be set to PWM mode at the most.
#### Syntax
`pwm.setup(pin, clock, duty)`
#### Parameters
- `pin` 1~12, IO index
- `clock` 1~1000, pwm frequency
- `duty` 0~1023, pwm duty cycle, max 1023 (10bit)
#### Returns
`nil`
#### Example
```lua
-- set pin index 1 as pwm output, frequency is 100Hz, duty cycle is half.
pwm.setup(1, 100, 512)
```
#### See also
[pwm.start()](#pwmstart)
## pwm.start()
PWM starts, the waveform is applied to the GPIO pin.
#### Syntax
`pwm.start(pin)`
####Parameters
`pin` 1~12, IO index
#### Returns
`nil`
#### See also
[pwm.stop()](#pwmstop)
## pwm.stop()
Pause the output of the PWM waveform.
#### Syntax
`pwm.stop(pin)`
#### Parameters
`pin` 1~12, IO index
#### Returns
`nil`
#### See also
[pwm.start()](#pwmstart)

169
docs/en/modules/rtcfifo.md Normal file
View File

@ -0,0 +1,169 @@
# rtcfifo Module
The rtcfifo module implements a first-in,first-out storage intended for sensor readings. As the name suggests, it is backed by the [RTC](https://en.wikipedia.org/wiki/Real-time_clock) user memory and as such survives deep sleep cycles. Conceptually it can be thought of as a cyclic array of `{ timestamp, name, value }` tuples. Internally it uses a space-optimized storage format to allow the greatest number of samples to be kept. This comes with several trade-offs, and as such is not a one-solution-fits-all. Notably:
- Timestamps are stored with second-precision.
- Sample frequency must be at least once every 8.5 minutes. This is a side-effect of delta-compression being used for the time stamps.
- Values are limited to 16 bits of precision, but have a separate field for storing an E<sup>-n</sup> multiplier. This allows for high fidelity even when working with very small values. The effective range is thus 1E<sup>-7</sup> to 65535.
- Sensor names are limited to a maximum of 4 characters.
!!! note "Important:"
This module uses two sets of RTC memory slots, 10-20 for its control block, and a variable number of slots for samples and sensor names. By default these span 32-127, but this is configurable. Slots are claimed when [`rtcfifo.prepare()`](#rtcfifoprepare) is called.
This is a companion module to the [rtcmem](rtcmem.md) and [rtctime](rtctime.md) modules.
## rtcfifo.dsleep_until_sample()
When the rtcfifo module is compiled in together with the rtctime module, this convenience function is available. It allows for some measure of separation of concerns, enabling writing of modularized Lua code where a sensor reading abstraction may not need to be aware of the sample frequency (which is largely a policy decision, rather than an intrinsic of the sensor). Use of this function is effectively equivalent to [`rtctime.dsleep_aligned(interval_us, minsleep_us)`](rtctime.md#rtctimedsleep_aligned) where `interval_us` is what was given to [`rtcfifo.prepare()`](#rtcfifoprepare).
####Syntax
`rtcfifo.dsleep_until_sample(minsleep_us)`
####Parameter
`minsleep_us` minimum sleep time, in microseconds
####Example
```lua
-- deep sleep until it's time to take the next sample
rtcfifo.dsleep_until_sample(0)
```
####See also
[`rtctime.dsleep_aligned()`](rtctime.md#rtctimedsleep_aligned)
## rtcfifo.peek()
Reads a sample from the rtcfifo. An offset into the rtcfifo may be specified, but by default it reads the first sample (offset 0).
####Syntax:
`rtcfifo.peek([offset])`
####Parameters
`offset` Peek at sample at position `offset` in the fifo. This is a relative offset, from the current head. Zero-based. Default value is 0.
####Returns
The values returned match the input arguments used to [`rtcfifo.put()`](#rtcfifoput).
- `timestamp` timestamp in seconds
- `value` the value
- `neg_e` scaling factor
- `name` sensor name
If no sample is available (at the specified offset), nothing is returned.
####Example
```lua
local timestamp, value, neg_e, name = rtcfifo.peek()
```
## rtcfifo.pop()
Reads the first sample from the rtcfifo, and removes it from there.
####Syntax:
`rtcfifo.pop()`
####Parameters
none
####Returns
The values returned match the input arguments used to [`rtcfifo.put()`](#rtcfifoput).
- `timestamp` timestamp in seconds
- `value` the value
- `neg_e` scaling factor
- `name` sensor name
####Example
```lua
while rtcfifo.count() > 0 do
local timestamp, value, neg_e, name = rtcfifo.pop()
-- do something with the sample, e.g. upload to somewhere
end
```
## rtcfifo.prepare()
Initializes the rtcfifo module for use.
Calling [`rtcfifo.prepare()`](#rtcfifoprepare) unconditionally re-initializes the storage - any samples stored are discarded.
####Syntax
`rtcfifo.prepare([table])`
####Parameters
This function takes an optional configuration table as an argument. The following items may be configured:
- `interval_us` If wanting to make use of the [`rtcfifo.sleep_until_sample()`](#rtcfifosleep_until_sample) function, this field sets the sample interval (in microseconds) to use. It is effectively the first argument of [`rtctime.dsleep_aligned()`](rtctime.md#rtctimedsleep_aligned).
- `sensor_count` Specifies the number of different sensors to allocate name space for. This directly corresponds to a number of slots reserved for names in the variable block. The default value is 5, minimum is 1, and maximum is 16.
- `storage_begin` Specifies the first RTC user memory slot to use for the variable block. Default is 32. Only takes effect if `storage_end` is also specified.
- `storage_end` Specified the end of the RTC user memory slots. This slot number will *not* be touched. Default is 128. Only takes effect if `storage_begin` is also specified.
####Returns
`nil`
####Example
```lua
-- Initialize with default values
rtcfifo.prepare()
```
```lua
-- Use RTC slots 19 and up for variable storage
rtcfifo.prepare({storage_begin=21, storage_end=128})
```
####See also
[`rtcfifo.ready()`](#rtcfifoready)
####See also
[`rtcfifo.prepare()`](#rtcfifoprepare)
## rtcfifo.put()
Puts a sample into the rtcfifo.
If the rtcfifo has not been prepared, this function does nothing.
####Syntax
`rtcfifo.put(timestamp, value, neg_e, name)`
####Parameters
- `timestamp` Timestamp in seconds. The timestamp would typically come from [`rtctime.get()`](rtctime.md#rtctimeget).
- `value` The value to store.
- `neg_e` The effective value stored is valueE<sup>neg_e</sup>.
- `name` Name of the sensor. Only the first four (ASCII) characters of `name` are used.
Note that if the timestamp delta is too large compared to the previous sample stored, the rtcfifo evicts all earlier samples to store this one. Likewise, if `name` would mean there are more than the `sensor_count` (as specified to [`rtcfifo.prepare()`](#rtcfifoprepare)) names in use, the rtcfifo evicts all earlier samples.
####Returns
`nil`
####Example
```lua
-- Obtain a sample value from somewhere
local sample = ...
-- Store sample with no scaling, under the name "foo"
rtcfifo.put(rtctime.get(), sample, 0, "foo")
```
## rtcfifo.ready()
Returns non-zero if the rtcfifo has been prepared and is ready for use, zero if not.
####Syntax:
`rtcfifo.ready()`
####Parameters
none
####Returns
Non-zero if the rtcfifo has been prepared and is ready for use, zero if not.
####Example
```lua
-- Prepare the rtcfifo if not already done
if not rtcfifo.ready() then
rtcfifo.prepare()
end
```

59
docs/en/modules/rtcmem.md Normal file
View File

@ -0,0 +1,59 @@
# rtcmem Module
The rtcmem module provides basic access to the [RTC](https://en.wikipedia.org/wiki/Real-time_clock) (Real Time Clock) memory.
The RTC in the ESP8266 contains memory registers which survive a deep sleep, making them highly useful for keeping state across sleep cycles. Some of this memory is reserved for system use, but 128 slots (each 32bit wide) are available for application use. This module provides read and write access to these.
Due to the very limited amount of memory available, there is no mechanism for arbitrating use of particular slots. It is up to the end user to be aware of which memory is used for what, and avoid conflicts. Note that some Lua modules lay claim to certain slots.
This is a companion module to the [rtctime](rtctime.md) and [rtcfifo](rtcfifo.md) modules.
## rtcmem.read32()
Reads one or more 32bit values from RTC user memory.
#### Syntax
`rtcmem.read32(idx [, num])`
#### Parameters
- `idx` zero-based index to start reading from
- `num` number of slots to read (default 1)
#### Returns
The value(s) read from RTC user memory.
If `idx` is outside the valid range [0,127] this function returns nothing.
If `num` results in overstepping the end of available memory, the function only returns the data from the valid slots.
#### Example
```lua
val = rtcmem.read32(0) -- Read the value in slot 0
val1, val2 = rtcmem.read32(42, 2) -- Read the values in slots 42 and 43
```
#### See also
[`rtcmem.write32()`](#rtcmemwrite32)
## rtcmem.write32()
Writes one or more values to RTC user memory, starting at index `idx`.
Writing to indices outside the valid range [0,127] has no effect.
#### Syntax
`rtcmem.write32(idx, val [, val2, ...])`
#### Parameters
- `idx` zero-based index to start writing to. Auto-increments if multiple values are given.
- `val` value to store (32bit)
- `val2...` additional values to store (optional)
#### Returns
`nil`
#### Example
```lua
rtcmem.write32(0, 53) -- Store the value 53 in slot 0
rtcmem.write32(42, 2, 5, 7) -- Store the values 2, 5 and 7 into slots 42, 43 and 44, respectively.
```
#### See also
[`rtcmem.read32()`](#rtcmemread32)

114
docs/en/modules/rtctime.md Normal file
View File

@ -0,0 +1,114 @@
# rtctime Module
The rtctime module provides advanced timekeeping support for NodeMCU, including keeping time across deep sleep cycles (provided [`rtctime.dsleep()`](#rtctimedsleep) is used instead of [`node.dsleep()`](node.md#nodedsleep)). This can be used to significantly extend battery life on battery powered sensor nodes, as it is no longer necessary to fire up the RF module each wake-up in order to obtain an accurate timestamp.
This module is intended for use together with [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol) (Network Time Protocol) for keeping highly accurate real time at all times. Timestamps are available with microsecond precision, based on the Unix Epoch (1970/01/01 00:00:00).
Time keeping on the ESP8266 is technically quite challenging. Despite being named [RTC](https://en.wikipedia.org/wiki/Real-time_clock), the RTC is not really a Real Time Clock in the normal sense of the word. While it does keep a counter ticking while the module is sleeping, the accuracy with which it does so is *highly* dependent on the temperature of the chip. Said temperature changes significantly between when the chip is running and when it is sleeping, meaning that any calibration performed while the chip is active becomes useless mere moments after the chip has gone to sleep. As such, calibration values need to be deduced across sleep cycles in order to enable accurate time keeping. This is one of the things this module does.
Further complicating the matter of time keeping is that the ESP8266 operates on three different clock frequencies - 52MHz right at boot, 80MHz during regular operation, and 160MHz if boosted. This module goes to considerable length to take all of this into account to properly keep the time.
To enable this module, it needs to be given a reference time at least once (via [`rtctime.set()`](#rtctimeset)). For best accuracy it is recommended to provide a reference time twice, with the second time being after a deep sleep.
Note that while the rtctime module can keep time across deep sleeps, it *will* lose the time if the module is unexpectedly reset.
!!! note "Important:"
This module uses RTC memory slots 0-9, inclusive. As soon as [`rtctime.set()`](#rtctimeset) (or [`sntp.sync()`](sntp.md#sntpsync)) has been called these RTC memory slots will be used.
This is a companion module to the [rtcmem](rtcmem.md) and [SNTP](sntp.md) modules.
## rtctime.dsleep()
Puts the ESP8266 into deep sleep mode, like [`node.dsleep()`](node.md#nodedsleep). It differs from [`node.dsleep()`](node.md#nodedsleep) in the following ways:
- Time is kept across the deep sleep. I.e. [`rtctime.get()`](#rtctimeget) will keep working (provided time was available before the sleep).
- This call never returns. The module is put to sleep immediately. This is both to support accurate time keeping and to reduce power consumption.
- The time slept will generally be considerably more accurate than with [`node.dsleep()`](node.md#nodedsleep).
- A sleep time of zero does not mean indefinite sleep, it is interpreted as a zero length sleep instead.
#### Syntax
`rtctime.dsleep(microseconds [, option])`
#### Parameters
- `microseconds` number of microseconds to sleep for. Maxmium value is 4294967295us, or ~71 minutes.
- `option` sleep option, see [`node.dsleep()`](node.md#nodedsleep) for specifics.
#### Returns
This function does not return.
#### Example
```lua
-- sleep for a minute
rtctime.dsleep(60*1000000)
```
```lua
-- sleep for 5 seconds, do not start RF on wakeup
rtctime.dsleep(5000000, 4)
```
## rtctime.dsleep_aligned()
For applications where it is necessary to take samples with high regularity, this function is useful. It provides an easy way to implement a "wake up on the next 5-minute boundary" scheme, without having to explicitly take into account how long the module has been active for etc before going back to sleep.
#### Syntax
`rtctime.dsleep(aligned_us, minsleep_us [, option])`
#### Parameters
- `aligned_us` boundary interval in microseconds
- `minsleep_us` minimum time that will be slept, if necessary skipping an interval. This is intended for sensors where a sample reading is started before putting the ESP8266 to sleep, and then fetched upon wake-up. Here `minsleep_us` should be the minimum time required for the sensor to take the sample.
- `option` as with `dsleep()`, the `option` sets the sleep option, if specified.
#### Example
```lua
-- sleep at least 3 seconds, then wake up on the next 5-second boundary
rtctime.dsleep_aligned(5*1000000, 3*1000000)
```
## rtctime.get()
Returns the current time. If current time is not available, zero is returned.
#### Syntax
`rtctime.get()`
#### Parameters
none
#### Returns
A two-value timestamp containing:
- `sec` seconds since the Unix epoch
- `usec` the microseconds part
#### Example
```lua
sec, usec = rtctime.get()
```
#### See also
[`rtctime.set()`](#rtctimeset)
## rtctime.set()
Sets the rtctime to a given timestamp in the Unix epoch (i.e. seconds from midnight 1970/01/01). If the module is not already keeping time, it starts now. If the module was already keeping time, it uses this time to help adjust its internal calibration values. Care is taken that timestamps returned from [`rtctime.get()`](#rtctimeget) *never go backwards*. If necessary, time is slewed and gradually allowed to catch up.
It is highly recommended that the timestamp is obtained via NTP (see [SNTP module](sntp.md)), GPS, or other highly accurate time source.
Values very close to the epoch are not supported. This is a side effect of keeping the memory requirements as low as possible. Considering that it's no longer 1970, this is not considered a problem.
#### Syntax
`rtctime.set(seconds, microseconds)`
#### Parameters
- `seconds` the seconds part, counted from the Unix epoch
- `microseconds` the microseconds part
#### Returns
`nil`
#### Example
```lua
-- Set time to 2015 July 9, 18:29:49
rtctime.set(1436430589, 0)
```
#### See also
[`sntp.sync()`](sntp.md#sntpsync)

40
docs/en/modules/sntp.md Normal file
View File

@ -0,0 +1,40 @@
# SNTP Module
The SNTP module implements a [Simple Network Time Procotol](https://en.wikipedia.org/wiki/Network_Time_Protocol#SNTP) client. This includes support for the "anycast" [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol) mode where, if supported by the NTP server(s) in your network, it is not necessary to even know the IP address of the NTP server.
When compiled together with the [rtctime](rtctime.md) module it also offers seamless integration with it, potentially reducing the process of obtaining NTP synchronization to a simple `sntp.sync()` call without any arguments.
## sntp.sync()
Attempts to obtain time synchronization.
#### Syntax
`sntp.sync([server_ip], [callback], [errcallback])`
#### Parameters
- `server_ip` if non-`nil`, that server is used. If `nil`, then the last contacted server is used. This ties in with the NTP anycast mode, where the first responding server is remembered for future synchronization requests. The easiest way to use anycast is to always pass nil for the server argument.
- `callback` Iif provided it will be invoked on a successful synchronization, with three parameters: seconds, microseconds, and server. Note that when the [rtctime](rtctime.md) module is available, there is no need to explicitly call [`rtctime.set()`](rtctime.md#rtctimeset) - this module takes care of doing so internally automatically, for best accuracy.
- `errcallback` failure callback with no parameters. The module automatically performs a number of retries before giving up and reporting the error.
#### Returns
`nil`
#### Example
```lua
-- Best effort, use the last known NTP server (or the NTP "anycast" address 224.0.1.1 initially)
sntp.sync()
```
```lua
-- Sync time with 192.168.0.1 and print the result, or that it failed
sntp.sync('192.168.0.1',
function(sec,usec,server)
print('sync', sec, usec, server)
end,
function()
print('failed!')
end
)
```
#### See also
[`rtctime.set()`](rtctime.md#rtctimeset)

173
docs/en/modules/spi.md Normal file
View File

@ -0,0 +1,173 @@
#spi module
All transactions for sending and receiving are most-significant-bit first and least-significant last.
For technical details of the underlying hardware refer to [metalphreak's ESP8266 HSPI articles](http://d.av.id.au/blog/tag/hspi/).
## High Level Functions
The high level functions provide a send & receive API for half- and
full-duplex mode. Sent and received data items are restricted to 1 - 32 bit
length and each data item is surrounded by (H)SPI CS inactive.
## spi.recv()
Receive data from SPI.
#### Syntax
`spi.recv(id, size[, default_data])`
#### Parameters
- `id` SPI ID number: 0 for SPI, 1 for HSPI
- `size` number of data items to be read
- `default_data` default data being sent on MOSI (all-1 if omitted)
#### Returns
String containing the bytes read from SPI.
####See also
[spi.send()](#spisend)
## spi.send()
Send data via SPI in half-duplex mode. Send & receive data in full-duplex mode.
#### Syntax
HALFDUPLEX:<br />
`wrote = spi.send(id, data1[, data2[, ..., datan]])`
FULLDUPLEX:<br />
`wrote[, rdata1[, ..., rdatan]] = spi.send(id, data1[, data2[, ..., datan]])`
#### Parameters
- `id` SPI ID number: 0 for SPI, 1 for HSPI
- `data` data can be either a string, a table or an integer number.<br/>Each data item is considered with `databits` number of bits.
#### Returns
- `wrote` number of written bytes
- `rdata` received data when configured with `spi.FULLDUPLEX`<br />Same data type as corresponding data parameter.
#### Example
```lua
=spi.send(1, 0, 255, 255, 255)
4 255 192 32 0
x = {spi.send(1, 0, 255, 255, 255)}
=x[1]
4
=x[2]
255
=x[3]
192
=x[4]
32
=x[5]
0
=x[6]
nil
=#x
5
_, _, x = spi.send(1, 0, {255, 255, 255})
=x[1]
192
=x[2]
32
=x[3]
0
```
#### See also
- [spi.setup()](#spisetup)
- [spi.recv()](#spirecv)
## spi.setup()
Set up the SPI configuration.
Refer to [Serial Peripheral Interface Bus](https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase) for details regarding the clock polarity and phase definition.
#### Syntax
`spi.setup(id, mode, cpol, cpha, databits, clock_div[, duplex_mode])`
#### Parameters
- `id` SPI ID number: 0 for SPI, 1 for HSPI
- `mode` select master or slave mode
- `spi.MASTER`
- `spi.SLAVE` - **not supported currently**
- `cpol` clock polarity selection
- `spi.CPOL_LOW`
- `spi.CPOL_HIGH` - **not supported currently**
- `cpha` clock phase selection
- `spi.CPHA_LOW`
- `spi.CPHA_HIGH`
- `databits` number of bits per data item 1 - 32
- `clock_div` SPI clock divider, f(SPI) = f(CPU) / `clock_div`
- `duplex_mode` duplex mode
- `spi.HALFDUPLEX` (default when omitted)
- `spi.FULLDUPLEX`
#### Returns
Number: 1
## Low Level Hardware Functions
The low level functions provide a hardware-centric API for application
scenarios that need to excercise more complex SPI transactions. The
programming model is built up around the HW send and receive buffers and SPI
transactions are initiated with full control over the hardware features.
## spi.get_miso()
Extract data items from MISO buffer after `spi.transaction()`.
#### Syntax
`data1[, data2[, ..., datan]] = spi.get_miso(id, offset, bitlen, num)`
#### Parameters
- `id` SPI ID number: 0 for SPI, 1 for HSPI
- `offset` bit offset into MISO buffer for first data item
- `bitlen` bit length of a single data item
- `num` number of data items to retrieve
####Returns
`num` data items
#### See also
[spi.transaction()](#spitransaction)
## spi.set_mosi()
Insert data items into MOSI buffer for `spi.transaction()`.
#### Syntax
`spi.set_mosi(id, offset, bitlen, data1[, data2[, ..., datan]])`
####Parameters
- `id` SPI ID number: 0 for SPI, 1 for HSPI
- `offset` bit offset into MOSI buffer for inserting data1 and subsequent items
- `bitlen` bit length of data1, data2, ...
- `data` data items where `bitlen` number of bits are considered for the transaction.
#### Returns
`nil`
#### See also
[spi.transaction()](#spitransaction)
## spi.transaction()
Start an SPI transaction, consisting of up to 5 phases:
1. Command
2. Address
3. MOSI
4. Dummy
5. MISO
#### Syntax
`spi.transaction(id, cmd_bitlen, cmd_data, addr_bitlen, addr_data, mosi_bitlen, dummy_bitlen, miso_bitlen)`
#### Parameters
- `id` SPI ID number: 0 for SPI, 1 for HSPI
- `cmd_bitlen` bit length of the command phase (0 - 16)
- `cmd_data` data for command phase
- `addr_bitlen` bit length for address phase (0 - 32)
- `addr_data` data for command phase
- `mosi_bitlen` bit length of the MOSI phase (0 - 512)
- `dummy_bitlen` bit length of the dummy phase (0 - 256)
- `miso_bitlen` bit length of the MISO phase (0 - 512) for half-duplex.<br />Full-duplex mode is activated with a negative value.
####Returns
`nil`
####See also
- [spi.set_mosi()](#spisetmosi)
- [spi.get_miso()](#spigetmiso)

273
docs/en/modules/tmr.md Normal file
View File

@ -0,0 +1,273 @@
# tmr Module
The tmr module allows access to simple timers, the system counter and uptime.
It is aimed at setting up regularly occurring tasks, timing out operations, and provide low-resolution deltas.
What the tmr module is *not* however, is a time keeping module. While most timeouts are expressed in milliseconds or even microseconds, the accuracy is limited and compounding errors would lead to rather inaccurate time keeping. Consider using the [rtctime](rtctime.md) module for "wall clock" time.
NodeMCU provides 7 timers, numbered 0-6. It is currently up to the user to keep track of which timers are used for what.
## tmr.alarm()
This is a convenience function combining [`tmr.register()`](#tmrregister) and [`tmr.start()`](#tmrstart) into a single call.
To free up the resources with this timer when done using it, call [`tmr.unregister()`](#tmrunregister) on it. For one-shot timers this is not necessary, unless they were stopped before they expired.
#### Parameters
- `id` timer id (0-6)
- `interval_ms` timer interval in milliseconds. Maximum value is 12884901. In SDKs <= 1.5.0 values >6871948 result in incorrect behaviour.
- `mode` timer mode:
- `tmr.ALARM_SINGLE` a one-shot alarm (and no need to call [`tmr.unregister()`](#tmrunregister))
- `tmr.ALARM_SEMI` manually repeating alarm (call [`tmr.start()`](#tmrstart) to restart)
- `tmr.ALARM_AUTO` automatically repeating alarm
#### Returns
`true` if the timer was started, `false` on error
#### Example
```lua
if not tmr.alarm(0, 5000, tmr.ALARM_SINGLE, function() print("hey there") end) then print("whoopsie") end
```
#### See also
- [`tmr.register()`](#tmrregister)
- [`tmr.start()`](#tmrstart)
- [`tmr.unregister()`](#tmrunregister)
## tmr.delay()
Busyloops the processor for a specified number of microseconds.
This is in general a **bad** idea, because nothing else gets to run, and the networking stack (and other things) can fall over as a result. The only time `tmr.delay()` may be appropriate to use is if dealing with a peripheral device which needs a (very) brief delay between commands, or similar. *Use with caution!*
Also note that the actual amount of time delayed for may be noticeably greater, both as a result of timing inaccuracies as well as interrupts which may run during this time.
#### Syntax
`tmr.delay(us)`
#### Parameters
`us` microseconds to busyloop for
#### Returns
`nil`
#### Example
```lua
tmr.delay(100)
```
## tmr.interval()
Changes a registered timer's expiry interval.
#### Syntax
`tmr.interval(id, interval_ms)`
#### Parameters
- `id` timer id (0-6)
- `interval_ms` new timer interval in milliseconds. Maximum value is 12884901. In SDKs <= 1.5.0 values >6871948 result in incorrect behaviour.
#### Returns
`nil`
#### Example
```lua
tmr.register(0, 5000, tmr.ALARM_SINGLE, function() print("hey there") end)
tmr.interval(0, 3000) -- actually, 3 seconds is better!
```
## tmr.now()
Returns the system counter, which counts in microseconds. Limited to 31 bits, after that it wraps around back to zero. That is essential if you use this function to [debounce or throttle GPIO input](https://github.com/hackhitchin/esp8266-co-uk/issues/2).
#### Syntax
`tmr.now()`
#### Parameters
none
#### Returns
the current value of the system counter
#### Example
```lua
print(tmr.now())
print(tmr.now())
```
## tmr.register()
Configures a timer and registers the callback function to call on expiry.
To free up the resources with this timer when done using it, call [`tmr.unregister()`](#tmrunregister) on it. For one-shot timers this is not necessary, unless they were stopped before they expired.
#### Syntax
`tmr.register(id, interval_ms, mode, func)`
#### Parameters
- `id` timer id (0-6)
- `interval_ms` timer interval in milliseconds. Maximum value is 12884901. In SDKs <= 1.5.0 values >6871948 result in incorrect behaviour.
- `mode` timer mode:
- `tmr.ALARM_SINGLE` a one-shot alarm (and no need to call [`tmr.unregister()`](#tmrunregister))
- `tmr.ALARM_SEMI` manually repeating alarm (call [`tmr.start()`](#tmrunregister) to restart)
- `tmr.ALARM_AUTO` automatically repeating alarm
Note that registering does *not* start the alarm.
#### Returns
`nil`
#### Example
```lua
tmr.register(0, 5000, tmr.ALARM_SINGLE, function() print("hey there") end)
tmr.start(0)
```
#### See also
[`tmr.alarm()`](#tmralarm)
## tmr.softwd()
Provides a simple software watchdog, which needs to be re-armed or disabled before it expires, or the system will be restarted.
#### Syntax
`tmr.softwd(timeout_s)`
#### Parameters
`timeout_s` watchdog timeout, in seconds. To disable the watchdog, use -1 (or any other negative value).
#### Returns
`nil`
#### Example
```lua
function on_success_callback()
tmr.softwd(-1)
print("Complex task done, soft watchdog disabled!")
end
tmr.softwd(5)
-- go off and attempt to do whatever might need a restart to recover from
complex_stuff_which_might_never_call_the_callback(on_success_callback)
```
## tmr.start()
Starts or restarts a previously configured timer.
#### Syntax
`tmr.start(id)`
#### Parameters
`id` timer id (0-6)
#### Returns
`true` if the timer was started, `false` on error
#### Example
```lua
tmr.register(0, 5000, tmr.ALARM_SINGLE, function() print("hey there") end)
if not tmr.start(0) then print("uh oh") end
```
#### See also
- [`tmr.register()`](#tmrregister)
- [`tmr.stop()`](#tmrstop)
- [`tmr.unregister()`](#tmrunregister)
## tmr.state()
Checks the state of a timer.
#### Syntax
`tmr.state(id)`
#### Parameters
`id` timer id (0-6)
#### Returns
(bool, int) or `nil`
If the specified timer is registered, returns whether it is currently started and its mode. If the timer is not registered, `nil` is returned.
#### Example
```lua
running, mode = tmr.state(0)
```
## tmr.stop()
Stops a running timer, but does *not* unregister it. A stopped timer can be restarted with [`tmr.start()`](#tmrstart).
#### Syntax
`tmr.stop(id)`
#### Parameters
`id` timer id (0-6)
#### Returns
`true` if the timer was stopped, `false` on error
#### Example
```lua
if not tmr.stop(2) then print("timer 2 not stopped, not registered?") end
```
#### See also
- [`tmr.register()`](#tmrregister)
- [`tmr.stop()`](#tmrstop)
- [`tmr.unregister()`](#tmrunregister)
## tmr.time()
Returns the system uptime, in seconds. Limited to 31 bits, after that it wraps around back to zero.
#### Syntax
`tmr.time()`
#### Parameters
none
#### Returns
the system uptime, in seconds, possibly wrapped around
#### Example
```lua
print("Uptime (probably):", tmr.time())
```
## tmr.unregister()
Stops the timer (if running) and unregisters the associated callback.
This isn't necessary for one-shot timers (`tmr.ALARM_SINGLE`), as those automatically unregister themselves when fired.
#### Syntax
`tmr.unregister(id)`
#### Parameters
`id` timer id (0-6)
#### Returns
`nil`
#### Example
```lua
tmr.unregister(0)
```
#### See also
[`tmr.register()`](#tmrregister)
## tmr.wdclr()
Feed the system watchdog.
*In general, if you ever need to use this function, you are doing it wrong.*
The event-driven model of NodeMCU means that there is no need to be sitting in hard loops waiting for things to occur. Rather, simply use the callbacks to get notified when somethings happens. With this approach, there should never be a need to manually feed the system watchdog.
#### Syntax
`tmr.wdclr()`
#### Parameters
none
#### Returns
`nil`

131
docs/en/modules/tsl2561.md Normal file
View File

@ -0,0 +1,131 @@
# TSL2561 Module
## tsl2561.getlux()
Reads sensor values from the device and returns calculated lux value.
#### Syntax
`tsl2561.getlux()`
#### Parameters
none
#### Returns
- `lux` the calculated illuminance in lux (lx)
- `status` value indicating success or failure as explained below:
* `tsl2561.TSL2561_OK`
* `tsl2561.TSL2561_ERROR_I2CINIT` can't initialize I²C bus
* `tsl2561.TSL2561_ERROR_I2CBUSY` I²C bus busy
* `tsl2561.TSL2561_ERROR_NOINIT` initialize I²C bus before calling function
* `tsl2561.TSL2561_ERROR_LAST`
#### Example
``` lua
status = tsl2561.init(5, 6, tsl2561.ADDRESS_FLOAT, tsl2561.PACKAGE_T_FN_CL)
if status == tsl2561.TSL2561_OK then
lux = tsl2561.getlux()
print("Illuminance: "..lux.." lx")
end
```
## tsl2561.getrawchannels()
Reads the device's 2 sensors and returns their values.
#### Syntax
`tsl2561.getrawchannels()`
#### Parameters
none
#### Returns
- `ch0` value of the broad spectrum sensor
- `ch1` value of the IR sensor
- `status` value indicating success or failure as explained below:
* `tsl2561.TSL2561_OK`
* `tsl2561.TSL2561_ERROR_I2CINIT` can't initialize I²C bus
* `tsl2561.TSL2561_ERROR_I2CBUSY` I²C bus busy
* `tsl2561.TSL2561_ERROR_NOINIT` initialize I²C bus before calling function
* `tsl2561.TSL2561_ERROR_LAST`
#### Example
``` lua
status = tsl2561.init(5, 6, tsl2561.ADDRESS_FLOAT, tsl2561.PACKAGE_T_FN_CL)
if status == tsl2561.TSL2561_OK then
ch0, ch1 = tsl2561.getrawchannels()
print("Raw values: "..ch0, ch1)
lux = tsl2561.getlux()
print("Illuminance: "..lux.." lx")
end
```
## tsl2561.init()
Initializes the device on pins sdapin & sclpin. Optionally also configures the devices address and package. Default: address pin floating (0x39) and FN package.
#### Syntax
` tsl2561.init(sdapin, sclpin[, address[, package]])`
#### Parameters
- `sdapin` pin number of the device's I²C sda connection
- `sclpin` pin number of the device's I²C scl connection
- `address` optional address of the device on the I²C bus
* `tsl2561.ADDRESS_GND`
* `tsl2561.ADDRESS_FLOAT` (default when omitted)
* `tsl2561.ADDRESS_VDD`
- `package` optional device's package type (slight difference in lux calculation)
* `tsl2561.PACKAGE_CS`
* `tsl2561.PACKAGE_T_FN_CL` (default when omitted)
#### Returns
`status` value indicating success or failure as explained below:
- `tsl2561.TSL2561_OK`
- `tsl2561.TSL2561_ERROR_I2CINIT` can't initialize I²C bus
- `tsl2561.TSL2561_ERROR_I2CBUSY` I²C bus busy
- `tsl2561.TSL2561_ERROR_NOINIT` Initialize I²C bus before calling function
- `tsl2561.TSL2561_ERROR_LAST`
#### Example
``` lua
status = tsl2561.init(5, 6, tsl2561.ADDRESS_FLOAT, tsl2561.PACKAGE_T_FN_CL)
if status == tsl2561.TSL2561_OK then
lux = tsl2561.getlux()
print("Illuminance: "..lux.." lx")
end
```
## tsl2561.settiming()
Sets the integration time and gain settings of the device. When `tls2561.init()` is called, these values default to 402 ms and no gain.
#### Syntax
`tsl2561.settiming(integration, gain)`
#### Parameters
- `integration` sets the device's integration period. Valid options are:
* `tsl2561.INTEGRATIONTIME_13MS`
* `tsl2561.INTEGRATIONTIME_101MS`
* `tsl2561.INTEGRATIONTIME_402MS` (default when omitted)
- `gain` sets the device's gain. Valid options are:
* `tsl2561.GAIN_1X` (default when omitted)
* `tsl2561.GAIN_16X`
#### Returns
`status` value indicating success or failure as explained below:
- `tsl2561.TSL2561_OK`
- `tsl2561.TSL2561_ERROR_I2CINIT` can't initialize I²C bus
- `tsl2561.TSL2561_ERROR_I2CBUSY` I²C bus busy
- `tsl2561.TSL2561_ERROR_NOINIT` initialize I²C bus before calling function
- `tsl2561.TSL2561_ERROR_LAST`
#### Example
``` lua
status = tsl2561.init(5, 6, tsl2561.ADDRESS_FLOAT, tsl2561.PACKAGE_T_FN_CL)
if status == tsl2561.TSL2561_OK then
status = tsl2561.settiming(tsl2561.INTEGRATIONTIME_101MS, tsl2561.GAIN_16X)
end
if status == tsl2561.TSL2561_OK then
lux = tsl2561.getlux()
print("Illuminance: "..lux.." lx")
end
```

434
docs/en/modules/u8g.md Normal file
View File

@ -0,0 +1,434 @@
# u8g Module
U8glib is a graphics library developed at [olikraus/u8glib](https://github.com/olikraus/u8glib) with support for many different displays. The NodeMCU firmware supports a subset of these.
I²C and SPI mode:
- sh1106_128x64
- ssd1306 - 128x64 and 64x48 variants
- ssd1309_128x64
- ssd1327_96x96_gr
- uc1611 - dogm240 and dogxl240 variants
SPI only:
- ld7032_60x32
- pcd8544_84x48
- pcf8812_96x65
- ssd1322_nhd31oled - bw and gr variants
- ssd1325_nhd27oled - bw and gr variants
- ssd1351_128x128 - gh and hicolor variants
- st7565_64128n - variants 64128n, dogm128/132, lm6059/lm6063, c12832/c12864
- uc1601_c128032
- uc1608 - 240x128 and 240x64 variants
- uc1610_dogxl160 - bw and gr variants
- uc1611 - dogm240 and dogxl240 variants
- uc1701 - dogs102 and mini12864 variants
This integration is based on [v1.18.1](https://github.com/olikraus/U8glib_Arduino/releases/tag/1.18.1).
## Overview
### I²C Connection
Hook up SDA and SCL to any free GPIOs. Eg. [u8g_graphics_test.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_graphics_test.lua) expects SDA=5 (GPIO14) and SCL=6 (GPIO12). They are used to set up nodemcu's I²C driver before accessing the display:
```lua
sda = 5
scl = 6
i2c.setup(0, sda, scl, i2c.SLOW)
```
### SPI connection
The HSPI module is used ([more information](http://d.av.id.au/blog/esp8266-hardware-spi-hspi-general-info-and-pinout/)), so certain pins are fixed:
- HSPI CLK = GPIO14
- HSPI MOSI = GPIO13
- HSPI MISO = GPIO12 (not used)
All other pins can be assigned to any available GPIO:
- CS
- D/C
- RES (optional for some displays)
Also refer to the initialization sequence eg in [u8g_graphics_test.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_graphics_test.lua):
```lua
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
```
### Library Usage
The Lua bindings for this library closely follow u8glib's object oriented C++ API. Based on the u8g class, you create an object for your display type.
SSD1306 via I²C:
```lua
sla = 0x3c
disp = u8g.ssd1306_128x64_i2c(sla)
```
SSD1306 via SPI:
```lua
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
```
This object provides all of u8glib's methods to control the display. Again, refer to [u8g_graphics_test.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_graphics_test.lua) to get an impression how this is achieved with Lua code. Visit the [u8glib homepage](https://github.com/olikraus/u8glib) for technical details.
### Displays
I²C and HW SPI based displays with support in u8glib can be enabled. To get access to the respective constructors, add the desired entries to the I²C or SPI display tables in [app/include/u8g_config.h](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/include/u8g_config.h):
```c
#define U8G_DISPLAY_TABLE_I2C \
U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_i2c) \
#define U8G_DISPLAY_TABLE_SPI \
U8G_DISPLAY_TABLE_ENTRY(ssd1306_128x64_hw_spi) \
U8G_DISPLAY_TABLE_ENTRY(pcd8544_84x48_hw_spi) \
U8G_DISPLAY_TABLE_ENTRY(pcf8812_96x65_hw_spi) \
```
### Fonts
u8glib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in [app/include/u8g_config.h](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/include/u8g_config.h) and recompile. Simply add the desired fonts to the font table:
```c
#define U8G_FONT_TABLE \
U8G_FONT_TABLE_ENTRY(font_6x10) \
U8G_FONT_TABLE_ENTRY(font_chikita)
```
They'll become available as `u8g.<font_name>` in Lua.
### Bitmaps
Bitmaps and XBMs are supplied as strings to `drawBitmap()` and `drawXBM()`. This off-loads all data handling from the u8g module to generic methods for binary files. See [u8g_bitmaps.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_bitmaps.lua).
In contrast to the source code based inclusion of XBMs into u8glib, it's required to provide precompiled binary files. This can be performed online with [Online-Utility's Image Converter](http://www.online-utility.org/image_converter.jsp): Convert from XBM to MONO format and upload the binary result with [nodemcu-uploader.py](https://github.com/kmpm/nodemcu-uploader).
## I²C Display Drivers
Initialize a display via I²C.
- `u8g.sh1106_128x64_i2c()`
- `u8g.ssd1306_128x64_i2c()`
- `u8g.ssd1306_64x48_i2c()`
- `u8g.ssd1309_128x64_i2c()`
- `u8g.ssd1327_96x96_gr_i2c()`
- `u8g.uc1611_dogm240_i2c()`
- `u8g.uc1611_dogxl240_i2c()`
####Syntax
`u8g.ssd1306_128x64_i2c(address)`
####Parameters
`address` I²C slave address of display
####Returns
u8g display object
####Example
```lua
sda = 5
scl = 6
i2c.setup(0, sda, scl, i2c.SLOW)
sla = 0x3c
disp = u8g.ssd1306_128x64_i2c(sla)
```
####See also
[SPI Display Drivers](#spi-display-drivers)
## SPI Display Drivers
Initialize a display via Hardware SPI.
- `u8g.ld7032_60x32_hw_spi()`
- `u8g.pcd8544_84x48_hw_spi()`
- `u8g.pcf8812_96x65_hw_spi()`
- `u8g.sh1106_128x64_hw_spi()`
- `u8g.ssd1306_128x64_hw_spi()`
- `u8g.ssd1306_64x48_hw_spi()`
- `u8g.ssd1309_128x64_hw_spi()`
- `u8g.ssd1322_nhd31oled_bw_hw_spi()`
- `u8g.ssd1322_nhd31oled_gr_hw_spi()`
- `u8g.ssd1325_nhd27oled_bw_hw_spi()`
- `u8g.ssd1325_nhd27oled_gr_hw_spi()`
- `u8g.ssd1327_96x96_gr_hw_spi()`
- `u8g.ssd1351_128x128_332_hw_spi()`
- `u8g.ssd1351_128x128gh_332_hw_spi()`
- `u8g.ssd1351_128x128_hicolor_hw_spi()`
- `u8g.ssd1351_128x128gh_hicolor_hw_spi()`
- `u8g.ssd1353_160x128_332_hw_spi()`
- `u8g.ssd1353_160x128_hicolor_hw_spi()`
- `u8g.st7565_64128n_hw_spi()`
- `u8g.st7565_dogm128_hw_spi()`
- `u8g.st7565_dogm132_hw_spi()`
- `u8g.st7565_lm6059_hw_spi()`
- `u8g.st7565_lm6063_hw_spi()`
- `u8g.st7565_nhd_c12832_hw_spi()`
- `u8g.st7565_nhd_c12864_hw_spi()`
- `u8g.uc1601_c128032_hw_spi()`
- `u8g.uc1608_240x128_hw_spi()`
- `u8g.uc1608_240x64_hw_spi()`
- `u8g.uc1610_dogxl160_bw_hw_spi()`
- `u8g.uc1610_dogxl160_gr_hw_spi()`
- `u8g.uc1611_dogm240_hw_spi()`
- `u8g.uc1611_dogxl240_hw_spi()`
- `u8g.uc1701_dogs102_hw_spi()`
- `u8g.uc1701_mini12864_hw_spi()`
#### Syntax
`u8g.ssd1306_128x64_spi(cs, dc[, res])`
#### Parameters
- `cs` GPIO pin for /CS
- `dc` GPIO pin for DC
- `res` GPIO pin for /RES (optional)
#### Returns
u8g display object
#### Example
```lua
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = u8g.ssd1306_128x64_hw_spi(cs, dc, res)
```
#### See also
[I²C Display Drivers](#i2c-display-drivers)
___
## Constants
Constants for various functions.
`u8g.DRAW_UPPER_RIGHT`, `u8g.DRAW_UPPER_LEFT`, `u8g.DRAW_LOWER_RIGHT`, `u8g.DRAW_LOWER_LEFT`, `u8g.DRAW_ALL`,
`u8g.MODE_BW`, `u8g.MODE_GRAY2BIT`
`u8g.font_6x10`, ...
# u8g.disp Sub-Module
## u8g.disp:begin()
See [u8glib begin()](https://github.com/olikraus/u8glib/wiki/userreference#begin).
## u8g.disp:drawBitmap()
Draw a bitmap at the specified x/y position (upper left corner of the bitmap).
Parts of the bitmap may be outside the display boundaries. The bitmap is specified by the array bitmap. A cleared bit means: Do not draw a pixel. A set bit inside the array means: Write pixel with the current color index. For a monochrome display, the color index 0 will usually clear a pixel and the color index 1 will set a pixel.
#### Syntax
`disp:drawBitmap(x, y, cnt, h, bitmap)`
#### Parameters
- `x` X-position (left position of the bitmap)
- `y` Y-position (upper position of the bitmap)
- `cnt` number of bytes of the bitmap in horizontal direction. The width of the bitmap is cnt*8.
- `h` height of the bitmap
- `bitmap` bitmap data supplied as string
#### Returns
`nil`
#### See also
- [u8glib drawBitmap()](https://github.com/olikraus/u8glib/wiki/userreference#drawbitmap)
- [lua_examples/u8glib/u8g_bitmaps.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_bitmaps.lua)
- [u8g.disp:drawXBM()](#u8gdispdrawxbm)
## u8g.disp:drawBox()
See [u8glib drawBox()](https://github.com/olikraus/u8glib/wiki/userreference#drawbox).
## u8g.disp:drawCircle()
See [u8glib drawCircle()](https://github.com/olikraus/u8glib/wiki/userreference#drawcircle).
## u8g.disp:drawDisc()
See [u8glib drawDisc()](https://github.com/olikraus/u8glib/wiki/userreference#drawdisc).
## u8g.disp:drawEllipse()
See [u8glib drawEllipse()](https://github.com/olikraus/u8glib/wiki/userreference#drawellipse).
## u8g.disp:drawFilledEllipse()
See [u8glib drawFilledEllipse](https://github.com/olikraus/u8glib/wiki/userreference#drawfilledellipse).
## u8g.disp:drawFrame()
See [u8glib drawFrame()](https://github.com/olikraus/u8glib/wiki/userreference#drawframe).
## u8g.disp:drawHLine()
See [u8glib drawHLine()](https://github.com/olikraus/u8glib/wiki/userreference#drawhline).
## u8g.disp:drawLine()
See [u8glib drawLine()](https://github.com/olikraus/u8glib/wiki/userreference#drawline).
## u8g.disp:drawPixel()
See [u8glib drawPixel()](https://github.com/olikraus/u8glib/wiki/userreference#drawpixel).
## u8g.disp:drawRBox()
See [u8glib drawRBox()](https://github.com/olikraus/u8glib/wiki/userreference#drawrbox).
## u8g.disp:drawRFrame()
See [u8glib drawRFrame()](https://github.com/olikraus/u8glib/wiki/userreference#drawrframe).
## u8g.disp:drawStr()
See [u8glib drawStr()](https://github.com/olikraus/u8glib/wiki/userreference#drawstr).
## u8g.disp:drawStr90()
See [u8glib drawStr90](https://github.com/olikraus/u8glib/wiki/userreference#drawstr90).
## u8g.disp:drawStr180()
See [u8glib drawStr180()](https://github.com/olikraus/u8glib/wiki/userreference#drawstr180).
## u8g.disp:drawStr270()
See [u8glib drawStr270()](https://github.com/olikraus/u8glib/wiki/userreference#drawstr270).
## u8g.disp:drawTriangle()
See [u8glib drawTriangle()](https://github.com/olikraus/u8glib/wiki/userreference#drawtriangle).
## u8g.disp:drawVLine()
See [u8glib drawVLine()](https://github.com/olikraus/u8glib/wiki/userreference#drawvline).
## u8g.disp:drawXBM()
Draw a XBM Bitmap. Position (x,y) is the upper left corner of the bitmap.
XBM contains monochrome, 1-bit bitmaps. This procedure only draws pixel values 1. The current color index is used for drawing (see setColorIndex). Pixel with value 0 are not drawn (transparent).
Bitmaps and XBMs are supplied as strings to `drawBitmap()` and `drawXBM()`. This off-loads all data handling from the u8g module to generic methods for binary files. In contrast to the source code based inclusion of XBMs into u8glib, it's required to provide precompiled binary files. This can be performed online with [Online-Utility's Image Converter](http://www.online-utility.org/image_converter.jsp): Convert from XBM to MONO format and upload the binary result with [nodemcu-uploader.py](https://github.com/kmpm/nodemcu-uploader) or [ESPlorer](http://esp8266.ru/esplorer/).
#### Syntax
`disp:drawXBM(x, y, w, h, bitmap)`
#### Parameters
- `x` X-position (left position of the bitmap)
- `y` Y-position (upper position of the bitmap)
- `w` width of the bitmap
- `h` height of the bitmap
- `bitmap` XBM data supplied as string
#### Returns
`nil`
#### See also
- [u8glib drawXBM()](https://github.com/olikraus/u8glib/wiki/userreference#drawxbm)
- [lua_examples/u8glib/u8g_bitmaps.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_bitmaps.lua)
- [u8g.disp:drawBitmap()](#u8gdispdrawbitmap)
## u8g.disp:firstPage()
See [u8glib firstPage()](https://github.com/olikraus/u8glib/wiki/userreference#firstpage).
## u8g.disp:getColorIndex()
See [u8glib getColorIndex()](https://github.com/olikraus/u8glib/wiki/userreference#getcolorindex).
## u8g.disp:getFontAscent()
See [u8glib getFontAscent()](https://github.com/olikraus/u8glib/wiki/userreference#getfontascent).
## u8g.disp:getFontDescent()
See [u8glib getFontDescent()](https://github.com/olikraus/u8glib/wiki/userreference#getfontdescent).
## u8g.disp:getFontLineSpacing()
See [u8glib getFontLineSpacing()](https://github.com/olikraus/u8glib/wiki/userreference#getfontlinespacing).
## u8g.disp:getHeight()
See [u8glib getHeight()](https://github.com/olikraus/u8glib/wiki/userreference#getheight).
## u8g.disp:getMode()
See [u8glib getMode()](https://github.com/olikraus/u8glib/wiki/userreference#getmode).
## u8g.disp:getWidth()
See [u8glib getWidth()](https://github.com/olikraus/u8glib/wiki/userreference#getwidth).
## u8g.disp:getStrWidth()
See [u8glib getStrWidth](https://github.com/olikraus/u8glib/wiki/userreference#getstrwidth).
## u8g.disp:nextPage()
See [u8glib nextPage()(https://github.com/olikraus/u8glib/wiki/userreference#nextpage).
## u8g.disp:setColorIndex()
See [u8glib setColorIndex()](https://github.com/olikraus/u8glib/wiki/userreference#setcolortndex).
## u8g.disp:setDefaultBackgroundColor()
See [u8glib setDefaultBackgroundColor()](https://github.com/olikraus/u8glib/wiki/userreference#setdefaultbackgroundcolor).
## u8g.disp:setDefaultForegroundColor()
See [u8glib setDefaultForegroundColor()](https://github.com/olikraus/u8glib/wiki/userreference#setdefaultforegroundcolor).
## u8g.disp:setFont()
u8glib comes with a wide range of fonts for small displays.
Since they need to be compiled into the firmware image, you'd need to include them in `app/include/u8g_config.h` and recompile. Simply add the desired fonts to the font table:
```c
#define U8G_FONT_TABLE \
U8G_FONT_TABLE_ENTRY(font_6x10) \
U8G_FONT_TABLE_ENTRY(font_chikita)
```
They'll be available as `u8g.<font_name>` in Lua.
#### Syntax
`disp:setFont(font)`
#### Parameters
`font` Constant to indentify pre-compiled font
#### Returns
`nil`
#### Example
```lua
disp:setFont(u8g.font_6x10)
```
#### See also
- [u8glib setFont()](https://github.com/olikraus/u8glib/wiki/userreference#setfont)
## u8g.disp:setFontLineSpacingFactor()
See [u8glib setFontLineSpacingFactor()](https://github.com/olikraus/u8glib/wiki/userreference#setfontlinespacingfactor).
## u8g.disp:setFontPosBaseline()
See [u8glib setFontPosBaseline()](https://github.com/olikraus/u8glib/wiki/userreference#setfontposbaseline).
## u8g.disp:setFontPosBottom()
See [u8glib setFontPosBottom()](https://github.com/olikraus/u8glib/wiki/userreference#setfontposbottom).
## u8g.disp:setFontPosCenter()
See [u8glib setFontPosCenter()](https://github.com/olikraus/u8glib/wiki/userreference#setfontposcenter).
## u8g.disp:setFontPosTop()
See [u8glib setFontPosTop()](https://github.com/olikraus/u8glib/wiki/userreference#setfontpostop).
## u8g.disp:setFontRefHeightAll()
See [u8glib setFontRefHeightAll()](https://github.com/olikraus/u8glib/wiki/userreference#setfontrefheightall).
## u8g.disp:setFontRefHeightExtendedText()
See [u8glib setFontRefHeightExtendedText()](https://github.com/olikraus/u8glib/wiki/userreference#setfontrefheightextendedtext).
## u8g.disp:setFontRefHeightText()
See [u8glib setFontRefHeightText()](https://github.com/olikraus/u8glib/wiki/userreference#setfontrefheighttext).
## u8g.disp:setRot90()
See [u8glib setRot90()](https://github.com/olikraus/u8glib/wiki/userreference#setrot90).
## u8g.disp:setRot180()
See [u8glib setRot180()](https://github.com/olikraus/u8glib/wiki/userreference#setrot180).
## u8g.disp:setRot270()
See [u8glib setRot270()](https://github.com/olikraus/u8glib/wiki/userreference#setrot270).
## u8g.disp:setScale2x2()
See [u8glib setScale2x2()](https://github.com/olikraus/u8glib/wiki/userreference#setscale2x2).
## u8g.disp:sleepOn()
See [u8glib sleepOn()](https://github.com/olikraus/u8glib/wiki/userreference#sleepon).
## u8g.disp:sleepOff()
See [u8glib sleepOff()](https://github.com/olikraus/u8glib/wiki/userreference#sleepoff).
## u8g.disp:undoRotation()
See [u8glib undoRotation()](https://github.com/olikraus/u8glib/wiki/userreference#undorotation).
## u8g.disp:undoScale()
See [u8glib undoScale()](https://github.com/olikraus/u8glib/wiki/userreference#undoscale).
## Unimplemented Functions
- Cursor handling
- disableCursor()
- enableCursor()
- setCursorColor()
- setCursorFont()
- setCursorPos()
- setCursorStyle()
- General functions
- setContrast()
- setPrintPos()
- setHardwareBackup()
- setRGB()
- setDefaultMidColor()

103
docs/en/modules/uart.md Normal file
View File

@ -0,0 +1,103 @@
# UART Module
The [UART](https://en.wikipedia.org/wiki/Universal_asynchronous_receiver/transmitter) (Universal asynchronous receiver/transmitter) module allows configuration of and communication over the UART serial port.
## uart.alt()
Change UART pin assignment.
#### Syntax
`uart.alt(on)`
#### Parameters
`on`:
- `0` use standard pins
- `1` use alternate pins GPIO13 and GPIO15
#### Returns
`nil`
## uart.on()
Sets the callback function to handle UART events.
Currently only the "data" event is supported.
#### Syntax
`uart.on(method, [number/end_char], [function], [run_input])`
#### Parameters
- `method` "data", data has been received on the UART
- `number/end_char`
- if pass in a number n<255, the callback will called when n chars are received.
- if n=0, will receive every char in buffer.
- if pass in a one char string "c", the callback will called when "c" is encounterd, or max n=255 received.
- `function` callback function, event "data" has a callback like this: `function(data) end`
- `run_input` 0 or 1. If 0, input from UART will not go into Lua interpreter, can accept binary data. If 1, input from UART will go into Lua interpreter, and run.
To unregister the callback, provide only the "data" parameter.
#### Returns
`nil`
#### Example
```lua
-- when 4 chars is received.
uart.on("data", 4,
function(data)
print("receive from uart:", data)
if data=="quit" then
uart.on("data") -- unregister callback function
end
end, 0)
-- when '\r' is received.
uart.on("data", "\r",
function(data)
print("receive from uart:", data)
if data=="quit\r" then
uart.on("data") -- unregister callback function
end
end, 0)
```
## uart.setup()
(Re-)configures the communication parameters of the UART.
#### Syntax
`uart.setup(id, baud, databits, parity, stopbits, echo)`
#### Parameters
- `id` always zero, only one uart supported
- `baud` one of 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 74880, 115200, 230400, 460800, 921600, 1843200, 2686400
- `databits` one of 5, 6, 7, 8
- `parity` `uart.PARITY_NONE`, `uart.PARITY_ODD`, or `uart.PARITY_EVEN`
- `stopbits` `uart.STOPBITS_1`, `uart.STOPBITS_1_5`, or `uart.STOPBITS_2`
- `echo` if 0, disable echo, otherwise enable echo
#### Returns
configured baud rate (number)
#### Example
```lua
-- configure for 9600, 8N1, with echo
uart.setup(0, 9600, 8, uart.PARITY_NONE, uart.STOPBITS_1, 1)
```
## uart.write()
Write string or byte to the UART.
#### Syntax
`uart.write(id, data1 [, data2, ...])`
#### Parameters
- `id` always 0, only one UART supported
- `data1`... string or byte to send via UART
#### Returns
`nil`
#### Example
```lua
uart.write(0, "Hello, world\n")
```

266
docs/en/modules/ucg.md Normal file
View File

@ -0,0 +1,266 @@
# ucg Module
Ucglib is a graphics library developed at [olikraus/ucglib](https://github.com/olikraus/ucglib) with support for color TFT displays. The NodeMCU firmware supports a subset of these:
- ILI9163
- ILI9341
- PCF8833
- SEPS225
- SSD1331
- SSD1351
- ST7735
This integration is based on [v1.3.3](https://github.com/olikraus/Ucglib_Arduino/releases/tag/v1.3.3).
## Overview
### SPI Connection
The HSPI module is used ([more information](http://d.av.id.au/blog/esp8266-hardware-spi-hspi-general-info-and-pinout/)), so certain pins are fixed:
* HSPI CLK = GPIO14
* HSPI MOSI = GPIO13
* HSPI MISO = GPIO12 (not used)
All other pins can be assigned to any available GPIO:
* CS
* D/C
* RES (optional for some displays)
Also refer to the initialization sequence eg in [GraphicsTest.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/ucglib/GraphicsRest.lua):
```lua
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 8)
```
### Library Usage
The Lua bindings for this library closely follow ucglib's object oriented C++ API. Based on the ucg class, you create an object for your display type.
ILI9341 via SPI:
```lua
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = ucg.ili9341_18x240x320_hw_spi(cs, dc, res)
```
This object provides all of ucglib's methods to control the display.
Again, refer to [GraphicsTest.lua](https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/ucglib/GraphicsTest.lua) to get an impression how this is achieved with Lua code. Visit the [ucglib homepage](https://github.com/olikraus/ucglib) for technical details.
### Displays
To get access to the display constructors, add the desired entries to the display table in [app/include/ucg_config.h](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/include/ucg_config.h):
```c
#define UCG_DISPLAY_TABLE \
UCG_DISPLAY_TABLE_ENTRY(ili9341_18x240x320_hw_spi, ucg_dev_ili9341_18x240x320, ucg_ext_ili9341_18) \
UCG_DISPLAY_TABLE_ENTRY(st7735_18x128x160_hw_spi, ucg_dev_st7735_18x128x160, ucg_ext_st7735_18) \
```
### Fonts
ucglib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in [app/include/ucg_config.h](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/include/ucg_config.h) and recompile. Simply add the desired fonts to the font table:
```c
#define UCG_FONT_TABLE \
UCG_FONT_TABLE_ENTRY(font_7x13B_tr) \
UCG_FONT_TABLE_ENTRY(font_helvB12_hr) \
UCG_FONT_TABLE_ENTRY(font_helvB18_hr) \
UCG_FONT_TABLE_ENTRY(font_ncenR12_tr) \
UCG_FONT_TABLE_ENTRY(font_ncenR14_hr)
```
They'll be available as `ucg.<font_name>` in Lua.
## Display Drivers
Initialize a display via Hardware SPI.
- `ili9163_18x128x128_hw_spi()`
- `ili9341_18x240x320_hw_spi()`
- `pcf8833_16x132x132_hw_spi()`
- `seps225_16x128x128_univision_hw_spi()`
- `ssd1351_18x128x128_hw_spi()`
- `ssd1351_18x128x128_ft_hw_spi()`
- `ssd1331_18x96x64_univision_hw_spi()`
- `st7735_18x128x160_hw_spi()`
#### Syntax
`ucg.st7735_18x128x160_hw_spi(cs, dc[, res])`
#### Parameters
- `cs` GPIO pin for /CS
- `dc` GPIO pin for DC
- `res` GPIO pin for /RES (optional)
#### Returns
ucg display object
#### Example
```lua
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, spi.DATABITS_8, 0)
cs = 8 -- GPIO15, pull-down 10k to GND
dc = 4 -- GPIO2
res = 0 -- GPIO16, RES is optional YMMV
disp = ucg.st7735_18x128x160_hw_spi(cs, dc, res)
```
## Constants
Constants for various functions.
`ucg.FONT_MODE_TRANSPARENT`, `ucg.FONT_MODE_SOLID`, `ucg.DRAW_UPPER_RIGHT`,
`ucg.DRAW_UPPER_LEFT`, `ucg.DRAW_LOWER_RIGHT`, `ucg.DRAW_LOWER_LEFT`, `ucg.DRAW_ALL`
`ucg.font_7x13B_tr`, ...
# ucg.disp Sub-Module
## ucg.disp:begin()
See [ucglib begin()](https://github.com/olikraus/ucglib/wiki/reference#begin).
## ucg.disp:clearScreen()
See [ucglib clearScreen()](https://github.com/olikraus/ucglib/wiki/reference#clearscreen).
## ucg.disp:draw90Line()
See [ucglib draw90Line()](https://github.com/olikraus/ucglib/wiki/reference#draw90line).
## ucg.disp:drawBox()
See [ucglib drawBox()](https://github.com/olikraus/ucglib/wiki/reference#drawbox).
## ucg.disp:drawCircle()
See [ucglib drawCircle()](https://github.com/olikraus/ucglib/wiki/reference#drawcircle).
## ucg.disp:drawDisc()
See [ucglib drawDisc()](https://github.com/olikraus/ucglib/wiki/reference#drawdisc).
## ucg.disp:drawFrame()
See [ucglib drawFrame()](https://github.com/olikraus/ucglib/wiki/reference#drawframe).
## ucg.disp:drawGlyph()
See [ucglib drawGlyph()](https://github.com/olikraus/ucglib/wiki/reference#drawglyph).
## ucg.disp:drawGradientBox()
See [ucglib drawGradientBox()](https://github.com/olikraus/ucglib/wiki/reference#drawgradientbox).
## ucg.disp:drawGradientLine()
See [ucglib drawGradientLine()](https://github.com/olikraus/ucglib/wiki/reference#drawgradientline).
## ucg.disp:drawHLine()
See [ucglib drawHLine()](https://github.com/olikraus/ucglib/wiki/reference#drawhline).
## ucg.disp:drawLine()
See [ucglib drawLine()](https://github.com/olikraus/ucglib/wiki/reference#drawline).
## ucg.disp:drawPixel()
See [ucglib drawPixel()](https://github.com/olikraus/ucglib/wiki/reference#drawpixel).
## ucg.disp:drawRBox()
See [ucglib drawRBox()](https://github.com/olikraus/ucglib/wiki/reference#drawrbox).
## ucg.disp:drawRFrame()
See [ucglib drawRFrame()](https://github.com/olikraus/ucglib/wiki/reference#drawrframe).
## ucg.disp:drawString()
See [ucglib drawString()](https://github.com/olikraus/ucglib/wiki/reference#drawstring).
## ucg.disp:drawTetragon()
See [ucglib drawTetragon()](https://github.com/olikraus/ucglib/wiki/reference#drawtetragon).
## ucg.disp:drawTriangle()
See [ucglib drawTriangle()](https://github.com/olikraus/ucglib/wiki/reference#drawrtiangle).
## ucg.disp:drawVLine()
See [ucglib drawVline()](https://github.com/olikraus/ucglib/wiki/reference#drawvline).
## ucg.disp:getFontAscent()
See [ucglib getFontAscent()](https://github.com/olikraus/ucglib/wiki/reference#getfontascent).
## ucg.disp:getFontDescent()
See [ucglib getFontDescent()](https://github.com/olikraus/ucglib/wiki/reference#getfontdescent).
## ucg.disp:getHeight()
See [ucglib getHeight()](https://github.com/olikraus/ucglib/wiki/reference#getheight).
## ucg.disp:getStrWidth()
See [ucglib getStrWidth()](https://github.com/olikraus/ucglib/wiki/reference#getstrwidth).
## ucg.disp:getWidth()
See [ucglib getWidth()](https://github.com/olikraus/ucglib/wiki/reference#getwidth).
## ucg.disp:print()
See [ucglib print()](https://github.com/olikraus/ucglib/wiki/reference#print).
## ucg.disp:setClipRange()
See [ucglib setClipRange()](https://github.com/olikraus/ucglib/wiki/reference#setcliprange).
## ucg.disp:setColor()
See [ucglib setColor()](https://github.com/olikraus/ucglib/wiki/reference#setcolor).
## ucg.disp:setFont()
ucglib comes with a wide range of fonts for small displays. Since they need to be compiled into the firmware image, you'd need to include them in [app/include/ucg_config.h](https://github.com/nodemcu/nodemcu-firmware/blob/master/app/include/ucg_config.h) and recompile. Simply add the desired fonts to the font table:
```c
#define UCG_FONT_TABLE \
UCG_FONT_TABLE_ENTRY(font_7x13B_tr) \
UCG_FONT_TABLE_ENTRY(font_helvB12_hr) \
UCG_FONT_TABLE_ENTRY(font_helvB18_hr) \
UCG_FONT_TABLE_ENTRY(font_ncenR12_tr) \
UCG_FONT_TABLE_ENTRY(font_ncenR14_hr)
```
They'll be available as `ucg.<font_name>` in Lua.
#### Syntax
`disp:setFont(font)`
#### Parameters
`font` constant to identify pre-compiled font
#### Returns
`nil`
#### Example
```lua
disp:setFont(ucg.font_7x13B_tr)
```
#### See also
[ucglib setFont()](https://github.com/olikraus/ucglib/wiki/reference#setfont)
## ucg.disp:setFontMode()
See [ucglib setFontMode()](https://github.com/olikraus/ucglib/wiki/reference#setfontmode).
## ucg.disp:setFontPosBaseline()
See [ucglib setFontPosBaseline()](https://github.com/olikraus/ucglib/wiki/reference#setfontposbaseline).
## ucg.disp:setFontPosBottom()
See [ucglib setFontPosBottom()](https://github.com/olikraus/ucglib/wiki/reference#setfontposbottom).
## ucg.disp:setFontPosCenter()
See [ucglib setFontPosCenter()](https://github.com/olikraus/ucglib/wiki/reference#setfontposcenter).
## ucg.disp:setFontPosTop()
See [ucglib setFontPosTop()](https://github.com/olikraus/ucglib/wiki/reference#setfontpostop).
## ucg.disp:setMaxClipRange()
See [ucglib setMaxClipRange()](https://github.com/olikraus/ucglib/wiki/reference#setmaxcliprange).
## ucg.disp:setPrintDir()
See [ucglib setPrintDir()](https://github.com/olikraus/ucglib/wiki/reference#setprintdir).
## ucg.disp:setPrintPos()
See [ucglib setPrintPos()](https://github.com/olikraus/ucglib/wiki/reference#setprintpos).
## ucg.disp:setRotate90()
See [ucglib setRotate90()](https://github.com/olikraus/ucglib/wiki/reference#setrotate90).
## ucg.disp:setRotate180()
See [ucglib setRotate180()](https://github.com/olikraus/ucglib/wiki/reference#setrotate180).
## ucg.disp:setRotate270()
See [ucglib setRotate270()](https://github.com/olikraus/ucglib/wiki/reference#setrotate270).
## ucg.disp:setScale2x2()
See [ucglib setScale2x2()](https://github.com/olikraus/ucglib/wiki/reference#setscale2x2).
## ucg.disp:undoClipRange()
See [ucglib undoClipRange()](https://github.com/olikraus/ucglib/wiki/reference#undocliprange).
## ucg.disp:undoRotate()
See [ucglib undoRotate()](https://github.com/olikraus/ucglib/wiki/reference#undorotate).
## ucg.disp:undoScale()
See [ucglib undoScale()](https://github.com/olikraus/ucglib/wiki/reference#undoscale).

933
docs/en/modules/wifi.md Normal file
View File

@ -0,0 +1,933 @@
# WiFi Module
The NodeMCU WiFi control is spread across several tables:
- `wifi` for overall WiFi configuration
- [`wifi.sta`](#wifista-module) for station mode functions
- [`wifi.ap`](#wifiap-module) for wireless access point (WAP or simply AP) functions
- [`wifi.ap.dhcp`](#wifiapdhcp-module) for DHCP server control
## wifi.getchannel()
Gets the current WiFi channel.
#### Syntax
`wifi.getchannel()`
#### Parameters
`nil`
#### Returns
current WiFi channel
#### Example
```lua
print(wifi.getchannel())
```
## wifi.getmode()
Gets WiFi operation mode.
#### Syntax
`wifi.getmode()`
#### Parameters
`nil`
#### Returns
The WiFi mode, as one of the `wifi.STATION`, `wifi.SOFTAP`, `wifi.STATIONAP` or `wifi.NULLMODE` constants.
#### See also
[`wifi.setmode()`](#wifisetmode)
## wifi.getphymode()
Gets WiFi physical mode.
#### Syntax
`wifi.getpymode()`
#### Parameters
none
#### Returns
The current physical mode as one of `wifi.PHYMODE_B`, `wifi.PHYMODE_G` or `wifi.PHYMODE_N`.
#### See also
[`wifi.setphymode()`](#wifisetphymode)
## wifi.setmode()
Configures the WiFi mode to use. NodeMCU can run in one of four WiFi modes:
- Station mode, where the NodeMCU device joins an existing network
- Access point (AP) mode, where it creates its own network that others can join
- Station + AP mode, where it both creates its own network while at the same time being joined to another existing network
- WiFi off
When using the combined Station + AP mode, the same channel will be used for both networks as the radio can only listen on a single channel.
#### Syntax
`wifi.setmode(mode)`
#### Parameters
`mode` value should be one of
- `wifi.STATION` for when the device is connected to a WiFi router. This is often done to give the device access to the Internet.
- `wifi.SOFTAP` for when the device is acting *only* as an access point. This will allow you to see the device in the list of WiFi networks (unless you hide the SSID, of course). In this mode your computer can connect to the device, creating a local area network. Unless you change the value, the NodeMCU device will be given a local IP address of 192.168.4.1 and assign your computer the next available IP address, such as 192.168.4.2.
- `wifi.STATIONAP` is the combination of `wifi.STATION` and `wifi.SOFTAP`. It allows you to create a local WiFi connection *and* connect to another WiFi router.
- `wifi.NULLMODE` to switch off WiFi
#### Returns
current mode after setup
#### Example
```lua
wifi.setmode(wifi.STATION)
```
#### See also
[`wifi.getmode()`](#wifigetmode)
## wifi.setphymode()
Sets WiFi physical mode.
- `wifi.PHYMODE_B`
802.11b, more range, low Transfer rate, more current draw
- `wifi.PHYMODE_G`
802.11g, medium range, medium transfer rate, medium current draw
- `wifi.PHYMODE_N`
802.11n, least range, fast transfer rate, least current draw (STATION ONLY)
Information from the Espressif datasheet v4.3
| Parameters |Typical Power Usage|
|---------------------------------------------|-------------------|
|Tx 802.11b, CCK 11Mbps, P OUT=+17dBm | 170 mA |
|Tx 802.11g, OFDM 54Mbps, P OUT =+15dBm | 140 mA |
|Tx 802.11n, MCS7 65Mbps, P OUT =+13dBm | 120 mA |
|Rx 802.11b, 1024 bytes packet length, -80dBm | 50 mA |
|Rx 802.11g, 1024 bytes packet length, -70dBm | 56 mA |
|Rx 802.11n, 1024 bytes packet length, -65dBm | 56 mA |
#### Syntax
`wifi.setphymode(mode)`
#### Parameters
`mode` one of the following
- `wifi.PHYMODE_B`
- `wifi.PHYMODE_G`
- `wifi.PHYMODE_N`
#### Returns
physical mode after setup
#### See also
[`wifi.getphymode()`](#wifigetphymode)
## wifi.sleeptype()
Configures the WiFi modem sleep type.
#### Syntax
`wifi.sleeptype(type_wanted)`
#### Parameters
`type_wanted` one of the following:
- `wifi.NONE_SLEEP` to keep the modem on at all times
- `wifi.LIGHT_SLEEP` to allow the modem to power down under some circumstances
- `wifi.MODEM_SLEEP` to power down the modem as much as possible
#### Returns
The actual sleep mode set, as one of `wifi.NONE_SLEEP`, `wifi.LIGHT_SLEEP` or `wifi.MODEM_SLEEP`.
#### See also
- [`node.dsleep()`](node.md#nodedsleep)
- [`rtctime.dsleep()`](rtctime.md#rtctimedsleep)
## wifi.startsmart()
Starts to auto configuration, if success set up SSID and password automatically.
Intended for use with SmartConfig apps, such as Espressif's [Android & iOS app](https://github.com/espressifapp).
Only usable in `wifi.STATION` mode.
#### Syntax
`wifi.startsmart(type, callback)`
#### Parameters
- `type` 0 for ESP\_TOUCH, or 1 for AIR\_KISS.
- `callback` a callback function of the form `function(ssid, password) end` which gets called after configuration.
#### Returns
`nil`
#### Example
```lua
wifi.setmode(wifi.STATION)
wifi.startsmart(0,
function(ssid, password)
print(string.format("Success. SSID:%s ; PASSWORD:%s", ssid, password))
end
)
```
#### See also
[`wifi.stopsmart()`](#wifistopsmart)
## wifi.stopsmart()
Stops the smart configuring process.
#### Syntax
`wifi.stopsmart()`
#### Parameters
none
#### Returns
`nil`
#### See also
[`wifi.startsmart()`](#wifistartsmart)
# wifi.sta Module
## wifi.sta.autoconnect()
Auto connects to AP in station mode.
#### Syntax
`wifi.sta.autoconnect(auto)`
#### Parameters
`auto` 0 to disable auto connecting, 1 to enable auto connecting
#### Returns
`nil`
#### Example
```lua
wifi.sta.autoconnect(1)
```
#### See also
- [`wifi.sta.config()`](#wifistaconfig)
- [`wifi.sta.connect()`](#wifistaconnect)
- [`wifi.sta.disconnect()`](#wifistadisconnect)
## wifi.sta.config()
Sets the WiFi station configuration.
#### Syntax
`wifi.sta.config(ssid, password[, auto[, bssid]])`
#### Parameters
- `ssid` string which is less than 32 bytes.
- `password` string which is 8-64 or 0 bytes. Empty string indicates an open WiFi access point.
- `auto` value of 0 or 1 (default)
- 0, Disable auto connect and remain disconnected from access point
- 1, Enable auto connect and connect to access point
- `bssid` string that contains the MAC address of the access point (optional)
- You can set BSSID if you have multiple access points with the same SSID.
- Note: if you set BSSID for a specific SSID and would like to configure station to connect to the same SSID only without the BSSID requirement, you MUST first configure to station to a different SSID first, then connect to the desired SSID
- The following formats are valid:
- "DE-C1-A5-51-F1-ED"
- "AC-1D-1C-B1-0B-22"
- "DE AD BE EF 7A C0"
#### Returns
`nil`
#### Example
```lua
--Connect to access point automatically when in range
wifi.sta.config("myssid", "password")
--Connect to Unsecured access point automatically when in range
wifi.sta.config("myssid", "")
--Connect to access point, User decides when to connect/disconnect to/from AP
wifi.sta.config("myssid", "mypassword", 0)
wifi.sta.connect()
-- ... do some WiFi stuff
wifi.sta.disconnect()
--Connect to specific access point automatically when in range
wifi.sta.config("myssid", "mypassword", "12:34:56:78:90:12")
--Connect to specific access point, User decides when to connect/disconnect to/from AP
wifi.sta.config("myssid", "mypassword", 0, "12:34:56:78:90:12")
wifi.sta.connect()
-- ... do some WiFi stuff
wifi.sta.disconnect()
```
#### See also
- [`wifi.sta.connect()`](#wifistaconnect)
- [`wifi.sta.disconnect()`](#wifistadisconnect)
## wifi.sta.connect()
Connects to AP in station mode.
#### Syntax
`wifi.sta.connect()`
#### Parameters
none
#### Returns
`nil`
#### Example
```lua
wifi.sta.connect()
```
#### See also
- [`wifi.sta.disconnect()`](#wifistadisconnect)
- [`wifi.sta.config()`](#wifistaconfig)
## wifi.sta.disconnect()
Disconnects from AP in station mode.
#### Syntax
`wifi.sta.disconnect()`
#### Parameters
none
#### Returns
`nil`
#### See also
- [`wifi.sta.config()`](#wifistaconfig)
- [`wifi.sta.connect()`](#wifistaconnect)
## wifi.sta.eventMonReg()
Registers callbacks for WiFi station status events.
#### Syntax
- `wifi.sta.eventMonReg(wifi_status, function([previous_state]))`
- `wifi.sta.eventMonReg(wifi.status, "unreg")`
#### Parameters
- `wifi_status` WiFi status you would like to set callback for, one of:
- `wifi.STA_IDLE`
- `wifi.STA_CONNECTING`
- `wifi.STA_WRONGPWD`
- `wifi.STA_APNOTFOUND`
- `wifi.STA_FAIL`
- `wifi.STA_GOTIP`
- `function` function to perform when event occurs
- `"unreg"` unregister previously registered callback
- `previous_state` previous wifi_state(0 - 5)
#### Returns
`nil`
#### Example
```lua
--register callback
wifi.sta.eventMonReg(wifi.STA_IDLE, function() print("STATION_IDLE") end)
wifi.sta.eventMonReg(wifi.STA_CONNECTING, function() print("STATION_CONNECTING") end)
wifi.sta.eventMonReg(wifi.STA_WRONGPWD, function() print("STATION_WRONG_PASSWORD") end)
wifi.sta.eventMonReg(wifi.STA_APNOTFOUND, function() print("STATION_NO_AP_FOUND") end)
wifi.sta.eventMonReg(wifi.STA_FAIL, function() print("STATION_CONNECT_FAIL") end)
wifi.sta.eventMonReg(wifi.STA_GOTIP, function() print("STATION_GOT_IP") end)
--register callback: use previous state
wifi.sta.eventMonReg(wifi.STA_CONNECTING, function(previous_State)
if(previous_State==wifi.STA_GOTIP) then
print("Station lost connection with access point\n\tAttempting to reconnect...")
else
print("STATION_CONNECTING")
end
end)
--unregister callback
wifi.sta.eventMonReg(wifi.STA_IDLE, "unreg")
```
#### See also
- [`wifi.sta.eventMonStart()`](#wifistaeventmonstart)
- [`wifi.sta.eventMonStop()`](#wifistaeventmonstop)
## wifi.sta.eventMonStart()
Starts WiFi station event monitor.
#### Syntax
`wifi.sta.eventMonStart([ms])`
### Parameters
`ms` interval between checks in milliseconds, defaults to 150ms if not provided
#### Returns
`nil`
#### Example
```lua
--start WiFi event monitor with default interval
wifi.sta.eventMonStart()
--start WiFi event monitor with 100ms interval
wifi.sta.eventMonStart(100)
```
#### See also
- [`wifi.sta.eventMonReg()`](#wifistaeventmonreg)
- [`wifi.sta.eventMonStop()`](#wifistaeventmonstop)
-
## wifi.sta.eventMonStop()
Stops WiFi station event monitor.
#### Syntax
`wifi.sta.eventMonStop(["unreg all"])`
#### Parameters
`"unreg all"` unregister all previously registered functions
#### Returns
`nil`
#### Example
```lua
--stop WiFi event monitor
wifi.sta.eventMonStop()
--stop WiFi event monitor and unregister all callbacks
wifi.sta.eventMonStop("unreg all")
```
#### See also
- [`wifi.sta.eventMonReg()`](#wifistaeventmonreg)
- [`wifi.sta.eventMonStart()`](#wifistaeventmonstart)
## wifi.sta.getap()
Scans AP list as a Lua table into callback function.
#### Syntax
`wifi.sta.getap([[cfg], format,] callback(table))`
#### Parameters
- `cfg` table that contains scan configuration
- `ssid` SSID == nil, don't filter SSID
- `bssid` BSSID == nil, don't filter BSSID
- `channel` channel == 0, scan all channels, otherwise scan set channel (default is 0)
- `show_hidden` show_hidden == 1, get info for router with hidden SSID (default is 0)
- `format` select output table format, defaults to 0
- 0: old format (SSID : Authmode, RSSI, BSSID, Channel), any duplicate SSIDs will be discarded
- 1: new format (BSSID : SSID, RSSI, auth mode, Channel)
- `callback(table)` a callback function to receive the AP table when the scan is done. This function receives a table, the key is the BSSID, the value is other info in format: SSID, RSSID, auth mode, channel.
#### Returns
`nil`
#### Example
```lua
-- print AP list in old format (format not defined)
function listap(t)
for k,v in pairs(t) do
print(k.." : "..v)
end
end
wifi.sta.getap(listap)
-- Print AP list that is easier to read
function listap(t) -- (SSID : Authmode, RSSI, BSSID, Channel)
print("\n"..string.format("%32s","SSID").."\tBSSID\t\t\t\t RSSI\t\tAUTHMODE\tCHANNEL")
for ssid,v in pairs(t) do
local authmode, rssi, bssid, channel = string.match(v, "([^,]+),([^,]+),([^,]+),([^,]+)")
print(string.format("%32s",ssid).."\t"..bssid.."\t "..rssi.."\t\t"..authmode.."\t\t\t"..channel)
end
end
wifi.sta.getap(listap)
-- print AP list in new format
function listap(t)
for k,v in pairs(t) do
print(k.." : "..v)
end
end
wifi.sta.getap(1, listap)
-- Print AP list that is easier to read
function listap(t) -- (SSID : Authmode, RSSI, BSSID, Channel)
print("\n\t\t\tSSID\t\t\t\t\tBSSID\t\t\t RSSI\t\tAUTHMODE\t\tCHANNEL")
for bssid,v in pairs(t) do
local ssid, rssi, authmode, channel = string.match(v, "([^,]+),([^,]+),([^,]+),([^,]*)")
print(string.format("%32.s",ssid).."\t"..bssid.."\t "..rssi.."\t\t"..authmode.."\t\t\t"..channel)
end
end
wifi.sta.getap(1, listap)
--check for specific AP
function listap(t)
print("\n\t\t\tSSID\t\t\t\t\tBSSID\t\t\t RSSI\t\tAUTHMODE\t\tCHANNEL")
for bssid,v in pairs(t) do
local ssid, rssi, authmode, channel = string.match(v, "([^,]+),([^,]+),([^,]+),([^,]*)")
print(string.format("%32.s",ssid).."\t"..bssid.."\t "..rssi.."\t\t"..authmode.."\t\t\t"..channel)
end
end
scan_cfg = {}
scan_cfg.ssid = "myssid"
scan_cfg.bssid = "AA:AA:AA:AA:AA:AA"
scan_cfg.channel = 0
scan_cfg.show_hidden = 1
wifi.sta.getap(scan_cfg, 1, listap)
--get RSSI for currently configured AP
function listap(t)
for bssid,v in pairs(t) do
local ssid, rssi, authmode, channel = string.match(v, "([^,]+),([^,]+),([^,]+),([^,]*)")
print("CURRENT RSSI IS: "..rssi)
end
end
ssid, tmp, bssid_set, bssid=wifi.sta.getconfig()
scan_cfg = {}
scan_cfg.ssid = ssid
if bssid_set == 1 then scan_cfg.bssid = bssid else scan_cfg.bssid = nil end
scan_cfg.channel = wifi.getchannel()
scan_cfg.show_hidden = 0
ssid, tmp, bssid_set, bssid=nil, nil, nil, nil
wifi.sta.getap(scan_cfg, 1, listap)
```
#### See also
[`wifi.sta.getip()`](#wifistagetip)
## wifi.sta.getbroadcast()
Gets the broadcast address in station mode.
#### Syntax
`wifi.sta.getbroadcast()`
#### Parameters
`nil`
#### Returns
broadcast address as string, for example "192.168.0.255",
returns `nil` if IP address = "0.0.0.0".
#### See also
[`wifi.sta.getip()`](#wifistagetip)
## wifi.sta.getconfig()
Gets the WiFi station configuration.
#### Syntax
`wifi.sta.getconfig()`
#### Parameters
none
#### Returns
ssid, password, bssid_set, bssid
Note: If bssid_set is equal to 0 then bssid is irrelevant
#### Example
```lua
--Get current Station configuration
ssid, password, bssid_set, bssid=wifi.sta.getconfig()
print("\nCurrent Station configuration:\nSSID : "..ssid
.."\nPassword : "..password
.."\nBSSID_set : "..bssid_set
.."\nBSSID: "..bssid.."\n")
ssid, password, bssid_set, bssid=nil, nil, nil, nil
```
#### See also
- [`wifi.sta.connect()`](#wifistaconnect)
- [`wifi.sta.disconnect()`](#wifistadisconnect)
## wifi.sta.gethostname()
Gets current station hostname.
#### Syntax
`wifi.sta.gethostname()`
#### Parameters
none
#### Returns
currently configured hostname
#### Example
```lua
print("Current hostname is: \""..wifi.sta.gethostname().."\"")
```
## wifi.sta.getip()
Gets IP address, netmask, and gateway address in station mode.
#### Syntax
`wifi.sta.getip()`
#### Parameters
none
#### Returns
IP address, netmask, gateway address as string, for example "192.168.0.111". Returns `nil` if IP = "0.0.0.0".
#### Example
```lua
-- print current IP address, netmask, gateway
print(wifi.sta.getip())
-- 192.168.0.111 255.255.255.0 192.168.0.1
ip = wifi.sta.getip()
print(ip)
-- 192.168.0.111
ip, nm = wifi.sta.getip()
print(nm)
-- 255.255.255.0
```
#### See also
[`wifi.sta.getmac()`](#wifistagetmac)
## wifi.sta.getmac()
Gets MAC address in station mode.
#### Syntax
`wifi.sta.getmac()`
#### Parameters
none
#### Returns
MAC address as string e.g. "18-33-44-FE-55-BB"
#### See also
[`wifi.sta.getip()`](#wifistagetip)
## wifi.sta.sethostname()
Sets station hostname.
#### Syntax
`wifi.sta.sethostname(hostname)`
#### Parameters
`hostname` must only contain letters, numbers and hyphens('-') and be 32 characters or less with first and last character being alphanumeric
#### Returns
true if hostname was successfully set, false otherwise
#### Example
```lua
if (wifi.sta.sethostname("NodeMCU") == true) then
print("hostname was successfully changed")
else
print("hostname was not changed")
end
```
## wifi.sta.setip()
Sets IP address, netmask, gateway address in station mode.
#### Syntax
`wifi.sta.setip(cfg)`
#### Parameters
`cfg` table contain IP address, netmask, and gateway
```lua
{
ip = "192.168.0.111",
netmask = "255.255.255.0",
gateway = "192.168.0.1"
}
```
#### Returns
true if success, false otherwise
#### See also
[`wifi.sta.setmac()`](#wifistasetmac)
## wifi.sta.setmac()
Sets MAC address in station mode.
#### Syntax
`wifi.sta.setmac(mac)`
#### Parameters
MAC address in string e.g. "DE:AD:BE:EF:7A:C0"
#### Returns
true if success, false otherwise
#### Example
```lua
print(wifi.sta.setmac("DE:AD:BE:EF:7A:C0"))
```
#### See also
[`wifi.sta.setip()`](#wifistasetip)
## wifi.sta.status()
Gets the current status in station mode.
#### Syntax
`wifi.sta.status()`
#### Parameters
`nil`
#### Returns
number 0~5
- 0: STATION_IDLE,
- 1: STATION_CONNECTING,
- 2: STATION_WRONG_PASSWORD,
- 3: STATION_NO_AP_FOUND,
- 4: STATION_CONNECT_FAIL,
- 5: STATION_GOT_IP.
# wifi.ap Module
## wifi.ap.config()
Sets SSID and password in AP mode. Be sure to make the password at least 8 characters long! If you don't it will default to *no* password and not set the SSID! It will still work as an access point but use a default SSID like e.g. ESP_9997C3.
#### Syntax
`wifi.ap.config(cfg)`
#### Parameters
- `ssdi` SSID chars 1-32
- `pwd` password chars 8-64
- `auth` authentication one of AUTH\_OPEN, AUTH\_WPA\_PSK, AUTH\_WPA2\_PSK, AUTH\_WPA\_WPA2\_PSK, default = AUTH\_OPEN
- `channel` channel number 1-14 default = 6
- `hidden` 0 = not hidden, 1 = hidden, default 0
- `max` maximal number of connections 1-4 default=4
- `beacon` beacon interval time in range 100-60000, default = 100
#### Returns
`nil`
#### Example:
```lua
cfg={}
cfg.ssid="myssid"
cfg.pwd="mypassword"
wifi.ap.config(cfg)
```
## wifi.ap.getbroadcast()
Gets broadcast address in AP mode.
#### Syntax
`wifi.ap.getbroadcast()`
#### Parameters
none
#### Returns
broadcast address in string, for example "192.168.0.255",
returns `nil` if IP address = "0.0.0.0".
#### Example
```lua
bc = wifi.ap.getbroadcast()
print(bc)
-- 192.168.0.255
```
#### See also
[`wifi.ap.getip()`](#wifiapgetip)
## wifi.ap.getclient()
Gets table of clients connected to device in AP mode.
#### Syntax
`wifi.ap.getclient()`
#### Parameters
none
#### Returns
table of connected clients
#### Example
```lua
table={}
table=wifi.ap.getclient()
for mac,ip in pairs(table) do
print(mac,ip)
end
-- or shorter
for mac,ip in pairs(wifi.ap.getclient()) do
print(mac,ip)
end
```
## wifi.ap.getip()
Gets IP address, netmask and gateway in AP mode.
#### Syntax
`wifi.ap.getip()`
#### Parameters
none
#### Returns
IP address, netmask, gateway address as string, for example "192.168.0.111", returns `nil` if IP address = "0.0.0.0".
#### Example
```lua
-- print current ip, netmask, gateway
print(wifi.ap.getip())
-- 192.168.4.1 255.255.255.0 192.168.4.1
ip = wifi.ap.getip()
print(ip)
-- 192.168.4.1
ip, nm = wifi.ap.getip()
print(nm)
-- 255.255.255.0
ip, nm, gw = wifi.ap.getip()
print(gw)
-- 192.168.4.1
```
#### See also
- [`wifi.ap.getmac()`](#wifiapgetmac)
## wifi.ap.getmac()
Gets MAC address in AP mode.
#### Syntax
`wifi.ap.getmac()`
#### Parameters
none
#### Returns
MAC address as string, for example "1A-33-44-FE-55-BB"
#### See also
[`wifi.ap.getip()`](#wifiapgetip)
## wifi.ap.setip()
Sets IP address, netmask and gateway address in AP mode.
#### Syntax
`wifi.ap.setip(cfg)`
#### Parameters
`cfg` table contain IP address, netmask, and gateway
#### Returns
true if successful, false otherwise
#### Example
```lua
cfg =
{
ip="192.168.1.1",
netmask="255.255.255.0",
gateway="192.168.1.1"
}
wifi.ap.setip(cfg)
```
#### See also
[`wifi.ap.setmac()`](#wifiapsetmac)
## wifi.ap.setmac()
Sets MAC address in AP mode.
#### Syntax
`wifi.ap.setmac(mac)`
#### Parameters
MAC address in byte string, for example "AC-1D-1C-B1-0B-22"
#### Returns
true if success, false otherwise
#### Example
```lua
print(wifi.ap.setmac("AC-1D-1C-B1-0B-22"))
```
#### See also
[`wifi.ap.setip()`](#wifiapsetip)
# wifi.ap.dhcp Module
## wifi.ap.dhcp.config()
Configure the dhcp service. Currently only supports setting the start address of the dhcp address pool.
#### Syntax
`wifi.ap.dhcp.config(dhcp_config)`
#### Parameters
`dhcp_config` table containing the start-IP of the DHCP address pool, eg. "192.168.1.100"
#### Returns
`pool_startip`, `pool_endip`
#### Example
```lua
dhcp_config ={}
dhcp_config.start = "192.168.1.100"
wifi.ap.dhcp.config(dhcp_config)
```
## wifi.ap.dhcp.start()
Starts the DHCP service.
#### Syntax
`wifi.ap.dhcp.start()`
#### Parameters
none
#### Returns
boolean indicating success
## wifi.ap.dhcp.stop()
Stops the DHCP service.
#### Syntax
`wifi.ap.dhcp.stop()`
#### Parameters
none
#### Returns
boolean indicating success

37
docs/en/modules/ws2801.md Normal file
View File

@ -0,0 +1,37 @@
# WS2801 Module
## ws2801.init()
Initializes the module and sets the pin configuration.
#### Syntax
`ws2801.init(pin_clk, pin_data)`
#### Parameters
- `pin_clk` pin for the clock. Supported are GPIO 0, 2, 4, 5.
- `pin_data` pin for the data. Supported are GPIO 0, 2, 4, 5.
#### Returns
`nil`
## ws2801.write()
Sends a string of RGB Data in 24 bits to WS2801. Don't forget to call `ws2801.init()` before.
#### Syntax
`ws2801.write(string)`
####Parameters
- `string` payload to be sent to one or more WS2801.
It should be composed from an RGB triplet per element.
- `R1` the first pixel's red channel value (0-255)
- `G1` the first pixel's green channel value (0-255)
- `B1` the first pixel's blue channel value (0-255)<br />
... You can connect a lot of WS2801...
- `R2`, `G2`, `B2` are the next WS2801's Red, Green, and Blue channel values
#### Returns
`nil`
#### Example
```lua
ws2801.write(string.char(255,0,0, 0,255,0, 0,0,255))
```

53
docs/en/modules/ws2812.md Normal file
View File

@ -0,0 +1,53 @@
# WS2812 Module
## ws2812.write()
Send GRB data in 8 bits to a WS2812 chain.
#### Syntax
`ws2812.writegrb(pin, string)`
#### Parameters
- `pin` any GPIO pin 0, 1, 2, ...
- `string` payload to be sent to one or more WS2812 LEDs.
It should be composed from a GRB triplet per element.
- `G1` the first pixel's Green channel (0-255)
- `R1` the first pixel's Red channel (0-255)
- `B1` the first pixel's Blue channel (0-255)<br />
... You can connect a lot of WS2812 ...
- `G2`, `R2`, `B2` are the next WS2812's Green, Red, and Blue channel parameters
#### Returns
`nil`
```lua
g = 0
r = 255
b = 0
leds_grb = string.char(g,r,b, g,r,b)
ws2812.write(2, leds_grb) -- turn two WS2812Bs to red, connected to pin 2
```
## ws2812.writergb()
Send GRB data in 8bits to a WS2812 chain.
#### Syntax
`ws2812.writergb(pin, string)`
#### Parameters
- `pin` any GPIO pin 0, 1, 2, ...
- `string` payload to be sent to one or more WS2812 LEDs.
It should be composed from an RGB triplet per element.
- `R1` the first pixel's Red channel (0-255)
- `G1` the first pixel's Green channel (0-255)
- `B1` the first pixel's Blue channel (0-255)<br />
... You can connect a lot of WS2812 ...
- `R2`, `G2`, `B2` are the next WS2812's Red, Green, and Blue channel parameters
#### Returns
`nil`
#### Example
```lua
leds_rgb = string.char(255,0,0, 0,255,0, 0,0,255)
ws2812.writergb(2, leds_rgb) -- turn three WS2812Bs to red, green, and blue respectively
```

5
docs/en/start.md Normal file
View File

@ -0,0 +1,5 @@
# Getting started
## Obtain the firmware
[Build the firmware](build.html) or download it from ?
## Flash the firmware
There are a number of tools for flashing the firmware.

7
docs/en/support.md Normal file
View File

@ -0,0 +1,7 @@
The [issues list on GitHub](https://github.com/nodemcu/nodemcu-firmware/issues) is **not** the right place to ask for help. Use it to report bugs and to place feature requests. Questions like "how do I ..." or "I can't get this to work ..." should be directed to StackOverflow or esp8266.com.
## StackOverflow
StackOverflow is the perfect place to ask coding questions. Use one or several of the following tags: [esp8266](http://stackoverflow.com/tags/esp8266), [nodemcu](http://stackoverflow.com/tags/nodemcu) or [Lua](http://stackoverflow.com/tags/lua).
## esp8266.com Forums
esp8266.com has a few [NodeMCU specific forums](http://www.esp8266.com/viewforum.php?f=17) where a number of our active community members tend to hang out.

35
docs/en/upload.md Normal file
View File

@ -0,0 +1,35 @@
As with [flashing](flash.md) there are several ways to upload code from your computer to the device.
# ESPlorer
> The essential multiplatforms tools for any ESP8266 developer from luatool authors, including Lua for NodeMCU and MicroPython. Also, all AT commands are supported. Requires Java (Standard Edition - SE ver 7 and above) installed.
![ESPlorer](../img/ESPlorer.jpg "ESPlorer")
Source: https://github.com/4refr0nt/ESPlorer
Supported platforms: OS X, Linux, Windows, anything that runs Java
# nodemcu-uploader.py
> A simple tool for uploading files to the filesystem of an ESP8266 running NodeMCU as well as some other useful commands.
Source: https://github.com/kmpm/nodemcu-uploader
Supported platforms: OS X, Linux, Windows, anything that runs Python
# NodeMCU Studio
> THIS TOOL IS IN REALLY REALLY REALLY REALLY EARLY STAGE!!!!!!!!!!!!!!!!!!!!!!!!!!!
Source: https://github.com/nodemcu/nodemcu-studio-csharp
Supported platforms: Windows
# luatool
> Allow easy uploading of any Lua-based script into the ESP8266 flash memory with NodeMcu firmware
Source: https://github.com/4refr0nt/luatool
Supported platforms: OS X, Linux, Windows, anything that runs Python

BIN
docs/img/ESPlorer.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

BIN
docs/img/enduser-setup.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
docs/img/favicon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
docs/img/logo-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
docs/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

15
docs/index.md Normal file
View File

@ -0,0 +1,15 @@
# NodeMCU Documentation
NodeMCU is an [eLua](http://www.eluaproject.net/) based firmware for the [ESP8266 WiFi SOC from Espressif](http://espressif.com/en/products/esp8266/). The NodeMCU *firmware* is a companion project to the popular [NodeMCU dev kits](https://github.com/nodemcu/nodemcu-devkit-v1.0), ready-made open source development boards with ESP8266-12E chips.
## Up-To-Date Documentation
At the moment the only up-to-date documentation maintained by the current NodeMCU team is in [English](en/index.md). It is part of the source code repository (`/docs` subfolder) and kept in sync with the code.
We encourage you to help transferring the outdated translations (see below) into the repository.
## Outdated And Sparse Documentation
The following translations are based on outdated documentation, use them with caution. The links point to the [NodeMCU wiki on GitHub](https://github.com/nodemcu/nodemcu-firmware/wiki).
- Chinese, [中文](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_cn)
- Russian, [русский](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_ru)
- Spanish, [español](https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_es)

158
docs/js/extra.js Normal file
View File

@ -0,0 +1,158 @@
var nodemcu = nodemcu || {};
(function () {
'use strict';
//var languageCodeToNameMap = {en: 'English', de: 'Deutsch'};
var languageCodeToNameMap = {en: 'English'};
var languageNames = values(languageCodeToNameMap);
var defaultLanguageCode = 'en';
$(document).ready(function () {
addToc();
hideNavigationForAllButSelectedLanguage();
addLanguageSelectorToRtdFlyOutMenu();
});
/**
* Adds a TOC-style table to each page in the 'Modules' section.
*/
function addToc() {
var func, intro, tocHtmlTable;
if (isModulePage()) {
tocHtmlTable = '<table class="docutils">';
$('h2').each(function (index) {
// 'slice' cuts off the single permalink character at the end of the text (e.g. '¶')
func = $(this).text().slice(0, -1);
// get the first sentence of the paragraph directly below h2
intro = $(this).next().text();
intro = intro.substring(0, intro.indexOf('.') + 1);
tocHtmlTable += createTocTableRow(func, intro);
});
tocHtmlTable += '</table>';
$(tocHtmlTable).insertBefore($('h2').first())
}
function isModulePage() {
// if the breadcrumb contains 'Modules »' it must be an API page
return $("ul.wy-breadcrumbs li:contains('Modules »')").size() > 0;
}
function createTocTableRow(func, intro) {
// fragile attempt to auto-create the in-page anchor
var href = func.replace(/\.|:/g, '').replace('()', '').replace(' --', '-').replace(/ /g, '-');
var link = '<a href="#' + href.toLowerCase() + '">' + func + '</a>';
return '<tr><td>' + link + '</td><td>' + intro + '</td></tr>';
}
}
function hideNavigationForAllButSelectedLanguage() {
var selectedLanguageCode = determineSelectedLanguageCode();
var selectedLanguageName = languageCodeToNameMap[selectedLanguageCode];
// Finds all subnav elements and hides them if they're /language/ subnavs. Hence, all 'Modules' subnav elements
// won't be hidden.
// <ul class="subnav">
// <li><span>Modules</span></li>
// <li class="toctree-l1 ">
// <a class="" href="EN/modules/node/">node</a>
// </li>
$('.subnav li span').not(':contains(' + selectedLanguageName + ')').each(function (index) {
var spanElement = $(this);
if ($.inArray(spanElement.text(), languageNames) > -1) {
spanElement.parent().parent().hide();
}
});
}
/**
* Adds a language selector to the RTD fly-out menu found bottom left. Example:
*
* <dl>
* <dt>Languages</dt>
* <dd><a href="http://nodemcu.readthedocs.org/en/<branch>/de/">de</a></dd>
* <strong>
* <dd><a href="http://nodemcu.readthedocs.org/en/<branch>/en/">en</a></dd>
* </strong>
* </dl>
*
* UGLY! That fly-out menu is added by RTD with an AJAX call after page load. Hence, we need to
* react to the subsequent DOM manipulation using a DOM4 MutationObserver. The provided structure
* is as follows:
*
* <div class="rst-other-versions">
* <!-- Inserted RTD Footer -->
* <div class="injected">
*/
function addLanguageSelectorToRtdFlyOutMenu() {
var flyOutWrapper = $('.rst-other-versions');
// only relevant on RTD
if (flyOutWrapper.size() > 0) {
var observer = new MutationObserver(function (mutations) {
// since mutation on the target node was triggered we can safely assume the injected RTD div has now been added
var injectedDiv = $('.rst-other-versions .injected');
var selectedLanguageCode = determineSelectedLanguageCode();
var dl = document.createElement('dl');
var dt = document.createElement('dt');
dl.appendChild(dt);
dt.appendChild(document.createTextNode('Languages'));
for (var languageCode in languageCodeToNameMap) {
dl.appendChild(createLanguageLinkFor(languageCode, selectedLanguageCode === languageCode));
}
injectedDiv.prepend(dl);
// no need for that observer anymore
observer.disconnect();
});
// observed target node is the fly-out wrapper, the only event we care about is when children are modified
observer.observe(flyOutWrapper[0], {childList: true});
}
}
function createLanguageLinkFor(languageCode, isCurrentlySelected) {
var strong;
// split[0] is an '' because the path starts with the separator
var pathSegments = window.location.pathname.split('/');
var dd = document.createElement("dd");
var href = document.createElement("a");
href.setAttribute('href', '/' + pathSegments[1] + '/' + pathSegments[2] + '/' + languageCode);
href.appendChild(document.createTextNode(languageCode));
dd.appendChild(href);
if (isCurrentlySelected) {
strong = document.createElement("strong");
strong.appendChild(dd);
return strong;
} else {
return dd;
}
}
/**
* Analyzes the URL of the current page to find out what the selected language is. It's usually
* part of the location path. The code needs to distinguish between running MkDocs standalone
* and docs served from RTD. If no valid language could be determined the default language is
* returned.
*
* @returns 2-char language code
*/
function determineSelectedLanguageCode() {
var selectedLanguageCode, path = window.location.pathname;
if (window.location.origin.indexOf('readthedocs') > -1) {
// path is like /en/<branch>/<lang>/build/ -> extract 'lang'
// split[0] is an '' because the path starts with the separator
selectedLanguageCode = path.split('/')[3];
} else {
// path is like /<lang>/build/ -> extract 'lang'
selectedLanguageCode = path.substr(1, 2);
}
if (!selectedLanguageCode || selectedLanguageCode.length > 2) {
selectedLanguageCode = defaultLanguageCode;
}
return selectedLanguageCode;
}
function values(associativeArray) {
var values = [];
for (var key in associativeArray) {
if (associativeArray.hasOwnProperty(key)) {
values.push(associativeArray[key]);
}
}
return values;
}
}());

65
mkdocs.yml Normal file
View File

@ -0,0 +1,65 @@
site_name: NodeMCU Documentation
site_description: Description of the NodeMCU documentation
repo_url: https://github.com/nodemcu/nodemcu-firmware/
theme: readthedocs
strict: true
markdown_extensions:
#http://pythonhosted.org/Markdown/extensions/admonition.html
- admonition:
- toc:
permalink: True
#requird due to https://github.com/rtfd/readthedocs.org/issues/1313
#see http://mkdocs.readthedocs.org/en/latest/user-guide/styling-your-docs/#customising-a-theme
extra_css:
- css/extra.css
extra_javascript:
- js/extra.js
site_favicon: img/favicon.png
pages:
- Overview: 'index.md'
- English:
- Home: 'en/index.md'
- Building the firmware: 'en/build.md'
- Flashing the firmware: 'en/flash.md'
- Uploading code: 'en/upload.md'
- FAQ: 'en/faq.md'
- Support: 'en/support.md'
- Modules:
- 'adc': 'en/modules/adc.md'
- 'bit': 'en/modules/bit.md'
- 'bmp085': 'en/modules/bmp085.md'
- 'cjson': 'en/modules/cjson.md'
- 'coap': 'en/modules/coap.md'
- 'crypto': 'en/modules/crypto.md'
- 'dht': 'en/modules/dht.md'
- 'enduser setup': 'en/modules/enduser-setup.md'
- 'file': 'en/modules/file.md'
- 'gpio': 'en/modules/gpio.md'
- 'http': 'en/modules/http.md'
- 'hx711' : 'en/modules/hx711.md'
- 'i2c' : 'en/modules/i2c.md'
- 'mqtt': 'en/modules/mqtt.md'
- 'net': 'en/modules/net.md'
- 'node': 'en/modules/node.md'
- 'ow (1-Wire)': 'en/modules/ow.md'
- 'pwm' : 'en/modules/pwm.md'
- 'rtcmem': 'en/modules/rtcmem.md'
- 'rtctime': 'en/modules/rtctime.md'
- 'rtcfifo': 'en/modules/rtcfifo.md'
- 'sntp': 'en/modules/sntp.md'
- 'spi': 'en/modules/spi.md'
- 'tmr': 'en/modules/tmr.md'
- 'tsl2561': 'en/modules/tsl2561.md'
- 'u8g': 'en/modules/u8g.md'
- 'uart': 'en/modules/uart.md'
- 'ucg': 'en/modules/ucg.md'
- 'wifi': 'en/modules/wifi.md'
- 'ws2801': 'en/modules/ws2801.md'
- 'ws2812': 'en/modules/ws2812.md'
#- Deutsch:
# - Home: 'de/index.md'