Commit c8ac5cfb authored by Arnim Läuger's avatar Arnim Läuger Committed by GitHub
Browse files

Merge pull request #1980 from nodemcu/dev

2.1.0 master drop
parents 22e1adc4 787379f0
As with [flashing](flash.md) there are several ways to upload code from your computer to the device.
Note that the NodeMCU serial interface uses 115'200bps at boot time. To change the speed after booting, issue `uart.setup(0,9600,8,0,1,1)`. ESPlorer will do this automatically when changing the speed in the dropdown list. If the device panics and resets at any time, errors will be written to the serial interface at 115'200 bps.
!!! note
The NodeMCU serial interface uses 115'200bps at boot time. To change the speed after booting, issue `uart.setup(0,9600,8,0,1,1)`. If the device panics and resets at any time, errors will be written to the serial interface at 115'200 bps.
# Tools
Transferring application code to ESP8266/8285 is an essential task, one that you'll perform quite frequently. Hence, it does make sense to try a few different uploading tools until you find one you feel comfortable with. [https://frightanic.com/iot/tools-ides-nodemcu/](https://frightanic.com/iot/tools-ides-nodemcu/) lists almost a dozen classical uploaders - in addition to IDEs or IDE-like applications which of course transfer code as well.
The NodeMCU firmware team does not give any recommendations as for which uploader to use nor are there any "NodeMCU approved" tools. The below listed tools are just three, in no particular order, which seem popular and/or reasonably well maintained.
## ESPlorer
......@@ -12,7 +17,7 @@ Note that the NodeMCU serial interface uses 115'200bps at boot time. To change t
Source: [https://github.com/4refr0nt/ESPlorer](https://github.com/4refr0nt/ESPlorer)
Supported platforms: OS X, Linux, Windows, anything that runs Java
Supported platforms: macOS, Linux, Windows, anything that runs Java
## nodemcu-uploader.py
......@@ -20,23 +25,16 @@ Supported platforms: OS X, Linux, Windows, anything that runs Java
Source: [https://github.com/kmpm/nodemcu-uploader](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](https://github.com/nodemcu/nodemcu-studio-csharp)
Supported platforms: Windows
Supported platforms: macOS, Linux, Windows, anything that runs Python
## luatool
## NodeMCU-Tool
> Allow easy uploading of any Lua-based script into the ESP8266 flash memory with NodeMcu firmware
> Upload/Download Lua files to your ESP8266 module with NodeMCU firmware.
> Simple. Command Line. Cross-Platform. File Management. NodeMCU.
Source: [https://github.com/4refr0nt/luatool](https://github.com/4refr0nt/luatool)
Source: [https://github.com/andidittrich/NodeMCU-Tool](https://github.com/andidittrich/NodeMCU-Tool)
Supported platforms: OS X, Linux, Windows, anything that runs Python
Supported platforms: macOS, Linux Windows, anything that runs Node.js
# init.lua
You will see "lua: cannot open init.lua" printed to the serial console when the device boots after it's been freshly flashed. If NodeMCU finds a `init.lua` in the root of the file system it will execute it as part of the boot sequence (standard Lua feature). Hence, your application is initialized and triggered from `init.lua`. Usually you first set up the WiFi connection and only continue once that has been successful.
......@@ -58,24 +56,65 @@ function startup()
end
end
-- Define WiFi station event callbacks
wifi_connect_event = function(T)
print("Connection to AP("..T.SSID..") established!")
print("Waiting for IP address...")
if disconnect_ct ~= nil then disconnect_ct = nil end
end
wifi_got_ip_event = function(T)
-- Note: Having an IP address does not mean there is internet access!
-- Internet connectivity can be determined with net.dns.resolve().
print("Wifi connection is ready! IP address is: "..T.IP)
print("Startup will resume momentarily, you have 3 seconds to abort.")
print("Waiting...")
tmr.create():alarm(3000, tmr.ALARM_SINGLE, startup)
end
wifi_disconnect_event = function(T)
if T.reason == wifi.eventmon.reason.ASSOC_LEAVE then
--the station has disassociated from a previously connected AP
return
end
-- total_tries: how many times the station will attempt to connect to the AP. Should consider AP reboot duration.
local total_tries = 75
print("\nWiFi connection to AP("..T.SSID..") has failed!")
--There are many possible disconnect reasons, the following iterates through
--the list and returns the string corresponding to the disconnect reason.
for key,val in pairs(wifi.eventmon.reason) do
if val == T.reason then
print("Disconnect reason: "..val.."("..key..")")
break
end
end
if disconnect_ct == nil then
disconnect_ct = 1
else
disconnect_ct = disconnect_ct + 1
end
if disconnect_ct < total_tries then
print("Retrying connection...(attempt "..(disconnect_ct+1).." of "..total_tries..")")
else
wifi.sta.disconnect()
print("Aborting connection to AP!")
disconnect_ct = nil
end
end
-- Register WiFi Station event callbacks
wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, wifi_connect_event)
wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, wifi_got_ip_event)
wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, wifi_disconnect_event)
print("Connecting to WiFi access point...")
wifi.setmode(wifi.STATION)
wifi.sta.config(SSID, PASSWORD)
wifi.sta.config({ssid=SSID, pwd=PASSWORD, save=true})
-- wifi.sta.connect() not necessary because config() uses auto-connect=true by default
tmr.create():alarm(1000, tmr.ALARM_AUTO, function(cb_timer)
if wifi.sta.getip() == nil then
print("Waiting for IP address...")
else
cb_timer:unregister()
print("WiFi connection established, IP address: " .. wifi.sta.getip())
print("You have 3 seconds to abort")
print("Waiting...")
tmr.create():alarm(3000, tmr.ALARM_SINGLE, startup)
end
end)
```
Inspired by [https://github.com/ckuehnel/NodeMCU-applications](https://github.com/ckuehnel/NodeMCU-applications)
```
# Compiling Lua on your PC for Uploading
......
......@@ -38,7 +38,8 @@ var nodemcu = nodemcu || {};
}
function createTocTableRow(func, intro) {
// fragile attempt to auto-create the in-page anchor
var href = func.replace(/\.|:/g, '').replace('()', '').replace(' --', '-').replace(/ /g, '-');
// good tests: file.md,
var href = func.replace(/[\.:\(\)]/g, '').replace(/ --|, | /g, '-');
var link = '<a href="#' + href.toLowerCase() + '">' + func + '</a>';
return '<tr><td>' + link + '</td><td>' + intro + '</td></tr>';
}
......@@ -180,7 +181,7 @@ var nodemcu = nodemcu || {};
// 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 {
} else if (!window.location.href.startsWith('file://')) {
// path is like /<lang>/build/ -> extract 'lang'
selectedLanguageCode = path.substr(1, 2);
}
......@@ -220,4 +221,4 @@ var nodemcu = nodemcu || {};
}
return values;
}
}());
\ No newline at end of file
}());
......@@ -5,7 +5,7 @@ MEMORY
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40210000, len = 0xD0000
irom0_0_seg : org = 0x40210000, len = 0xE0000
}
PHDRS
......@@ -105,7 +105,7 @@ SECTIONS
/* SDK libraries that used in bootup process, interruption handling
* and other ways where flash cache (iROM) is unavailable: */
*libmain.a:*(.literal .text)
*libmain.a:*(.literal .literal.* .text .text.*)
*libnet80211.a:*(.literal .text)
*libphy.a:*(.literal .text)
*libpp.a:*(.literal .text)
......
......@@ -18,7 +18,7 @@ end
-- payload(json): {"cmd":xxx,"content":xxx}
function topic1func(m,pl)
print("get1: "..pl)
local pack = cjson.decode(pl)
local pack = sjson.decode(pl)
if pack.content then
if pack.cmd == "open" then file.open(pack.content,"w+")
elseif pack.cmd == "write" then file.write(pack.content)
......
--'
-- ds18b20 one wire example for NODEMCU (Integer firmware only)
-- NODEMCU TEAM
-- LICENCE: http://opensource.org/licenses/MIT
-- Vowstar <vowstar@nodemcu.com>
--'
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)
-- handle negative temperatures
if (t > 0x7fff) then
t = t - 0x10000
end
if (addr:byte(1) == 0x28) then
t = t * 625 -- DS18B20, 4 fractional bits
else
t = t * 5000 -- DS18S20, 1 fractional bit
end
local sign = ""
if (t < 0) then
sign = "-"
t = -1 * t
end
-- Separate integral and decimal portions, for integer firmware only
local t1 = string.format("%d", t / 10000)
local t2 = string.format("%04u", t % 10000)
local temp = sign .. t1 .. "." .. t2
print("Temperature= " .. temp .. " Celsius")
end
tmr.wdclr()
until false
else
print("Device family is not recognized.")
end
else
print("CRC is not valid!")
end
end
-- Somfy module example (beside somfy module requires also CJSON module)
-- Somfy module example (beside somfy module requires also SJSON module)
-- The rolling code number is stored in the file somfy.cfg. A cached write of the somfy.cfg file is implemented in order to reduce the number of write to the EEPROM memory. Together with the logic of the file module it should allow long lasting operation.
config_file = "somfy."
......@@ -43,7 +43,7 @@ function readconfig()
end
if not ln then ln = "{}" end
print("Configuration: "..ln)
config = cjson.decode(ln)
config = sjson.decode(ln)
config_saved = deepcopy(config)
end
......@@ -52,7 +52,7 @@ function writeconfighard()
file.remove(config_file.."bak")
file.rename(config_file.."cfg", config_file.."bak")
file.open(config_file.."cfg", "w+")
local ok, cfg = pcall(cjson.encode, config)
local ok, cfg = pcall(sjson.encode, config)
if ok then
file.writeline(cfg)
else
......@@ -68,8 +68,8 @@ function writeconfig()
local savenow = false
local savelater = false
--print("Config: "..cjson.encode(config))
--print("Config saved: "..cjson.encode(config))
--print("Config: "..sjson.encode(config))
--print("Config saved: "..sjson.encode(config))
local count = 0
for _ in pairs(config_saved) do count = count + 1 end
......@@ -134,7 +134,7 @@ end
--======================================================================================================--
if not config then readconfig() end
if #config == 0 then -- somfy.cfg does not exist
config = cjson.decode([[{"window1":{"rc":1,"address":123},"window2":{"rc":1,"address":124}}]])
config = sjson.decode([[{"window1":{"rc":1,"address":123},"window2":{"rc":1,"address":124}}]])
config_saved = deepcopy(config)
end
down('window1',
......
# tz module
This is a simple module that parses timezone files as found on unix systems. It is oriented around converting the current time. It can convert other times, but it is
rather less efficient as it maintains only a single cached entry in memory.
On my linux system, these files can be found in `/usr/share/zoneinfo`.
## tz.setzone()
This sets the timezone to be used in subsequent conversions
#### Syntax
`tz.setzone(timezone)`
#### Parameters
- `timezone` this is the timezone string. It must correspond to a file in the file system which is named timezone.zone.
#### Returns
true if the zone exists in the file system.
## tz.getoffset()
This gets the offset (in seconds) of the time passed as the argument.
#### Syntax
`tz.getoffset(time)`
#### Parameters
- `time` the number of seconds since the epoch. This is the same value as used by the `sntp` module.
#### Returns
- The number of seconds of offset. West of Greenwich is negative.
- The start time (in epoch seconds) of this offset.
- The end time (in epoch seconds) of this offset.
#### Example
```
tz = require('tz')
tz.setzone('eastern')
sntp.sync(nil, function(now)
local tm = rtctime.epoch2cal(now + tz.getoffset(now))
print(string.format("%04d/%02d/%02d %02d:%02d:%02d", tm["year"], tm["mon"], tm["day"], tm["hour"], tm["min"], tm["sec"]))
end)
```
## tz.getzones()
This returns a list of the available timezones in the file system.
#### Syntax
`tz.getzones()`
#### Returns
A list of timezones.
-- tz -- A simple timezone module for interpreting zone files
local M = {}
local tstart = 0
local tend = 0
local toffset = 0
local thezone = "eastern"
function M.setzone(zone)
thezone = zone
return M.exists(thezone)
end
function M.exists(zone)
return file.exists(zone .. ".zone")
end
function M.getzones()
local result = {}
for fn, _ in pairs(file.list()) do
local _, _, prefix = string.find(fn, "(.*).zone")
if prefix then
table.insert(result, prefix)
end
end
return result
end
function load(t)
local z = file.open(thezone .. ".zone", "r")
local hdr = z:read(20)
local magic = struct.unpack("c4 B", hdr)
if magic == "TZif" then
local lens = z:read(24)
local ttisgmt_count, ttisdstcnt, leapcnt, timecnt, typecnt, charcnt = struct.unpack("> LLLLLL", lens)
local times = z:read(4 * timecnt)
local typeindex = z:read(timecnt)
local ttinfos = z:read(6 * typecnt)
z:close()
local offset = 1
local tt
for i = 1, timecnt do
tt = struct.unpack(">l", times, (i - 1) * 4 + 1)
if t < tt then
offset = (i - 2)
tend = tt
break
end
tstart = tt
end
local tindex = struct.unpack("B", typeindex, offset + 1)
toffset = struct.unpack(">l", ttinfos, tindex * 6 + 1)
else
tend = 0x7fffffff
tstart = 0
end
end
function M.getoffset(t)
if t < tstart or t >= tend then
-- Ignore errors
local ok, msg = pcall(function ()
load(t)
end)
if not ok then
print (msg)
end
end
return toffset, tstart, tend
end
return M
------------------------------------------------------------------------------
-- DS18B20 query module
--
-- LICENCE: http://opensource.org/licenses/MIT
-- Vladimir Dronnikov <dronnikov@gmail.com>
--
-- Example:
-- dofile("ds18b20.lua").read(4, function(r) for k, v in pairs(r) do print(k, v) end end)
------------------------------------------------------------------------------
local M
do
local bit = bit
local format_addr = function(a)
return ("%02x-%02x%02x%02x%02x%02x%02x"):format(
a:byte(1),
a:byte(7), a:byte(6), a:byte(5),
a:byte(4), a:byte(3), a:byte(2)
)
end
local read = function(pin, cb, delay)
local ow = require("ow")
-- get list of relevant devices
local d = { }
ow.setup(pin)
ow.reset_search(pin)
while true do
tmr.wdclr()
local a = ow.search(pin)
if not a then break end
if ow.crc8(a) == 0 and
(a:byte(1) == 0x10 or a:byte(1) == 0x28)
then
d[#d + 1] = a
end
end
-- conversion command for all
ow.reset(pin)
ow.skip(pin)
ow.write(pin, 0x44, 1)
-- wait a bit
tmr.alarm(0, delay or 100, 0, function()
-- iterate over devices
local r = { }
for i = 1, #d do
tmr.wdclr()
-- read rom command
ow.reset(pin)
ow.select(pin, d[i])
ow.write(pin, 0xBE, 1)
-- read data
local x = ow.read_bytes(pin, 9)
if ow.crc8(x) == 0 then
local t = (x:byte(1) + x:byte(2) * 256)
-- negatives?
if bit.isset(t, 15) then t = 1 - bit.bxor(t, 0xffff) end
-- NB: temperature in Celsius * 10^4
t = t * 625
-- NB: due 850000 means bad pullup. ignore
if t ~= 850000 then
r[format_addr(d[i])] = t
end
d[i] = nil
end
end
cb(r)
end)
end
-- expose
M = {
read = read,
}
end
return M
# DS18B20 Module
## Require
```lua
ds18b20 = require("ds18b20")
```
## Release
```lua
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
<a id="ds18b20_setup"></a>
## readTemp()
Scans the bus for DS18B20 sensors, starts a readout (conversion) for all sensors and calls a callback function when all temperatures are available. Powered sensors are read at once first. Parasite-powered sensors are read one by one. The first parasite-powered sensor is read together with all powered sensors.
The module requires `ow` module.
The also module uses `encoder` module for printing debug information with more readable representation of sensor address (`encoder.toHex()`).
#### Syntax
`readTemp(callback, pin)`
#### Parameters
- `callback` function that receives all results when all conversions finish. The callback function has one parameter - an array addressed by sensor addresses and a value of the temperature (string for integer version).
- `pin` pin of the one-wire bus. If nil, GPIO0 (3) is used.
#### Returns
nil
#### Example
```lua
t = require("ds18b20")
pin = 3 -- gpio0 = 3, gpio2 = 4
function readout(temp)
for addr, temp in pairs(temp) do
print(string.format("Sensor %s: %s 'C", encoder.toHex(addr), temp))
end
-- Module can be released when it is no longer needed
t = nil
package.loaded["ds18b20"]=nil
end
-- t:readTemp(readout) -- default pin value is 3
t:readTemp(readout, pin)
if t.sens then
print("Total number of DS18B20 sensors: "..table.getn(t.sens))
for i, s in ipairs(t.sens) do
-- print(string.format(" sensor #%d address: %s%s", i, s.addr, s.parasite == 1 and " (parasite)" or ""))
print(string.format(" sensor #%d address: %s%s", i, encoder.toHex(s.addr), s.parasite == 1 and " (parasite)" or "")) -- readable address with Hex encoding is preferred when encoder module is available
end
end
```
-- encoder module is needed only for debug output; lines can be removed if no
-- debug output is needed and/or encoder module is missing
t = require("ds18b20")
pin = 3 -- gpio0 = 3, gpio2 = 4
-- ESP-01 GPIO Mapping
gpio0 = 3
gpio2 = 4
function readout(temp)
for addr, temp in pairs(temp) do
-- print(string.format("Sensor %s: %s 'C", addr, temp))
print(string.format("Sensor %s: %s °C", encoder.toHex(addr), temp)) -- readable address with base64 encoding is preferred when encoder module is available
end
t.setup(gpio0)
addrs = t.addrs()
if (addrs ~= nil) then
print("Total DS18B20 sensors: "..table.getn(addrs))
-- Module can be released when it is no longer needed
t = nil
package.loaded["ds18b20"]=nil
end
-- Just read temperature
print("Temperature: "..t.read().."'C")
-- Get temperature of first detected sensor in Fahrenheit
print("Temperature: "..t.read(nil,t.F).."'F")
-- Query the second detected sensor, get temperature in Kelvin
if (table.getn(addrs) >= 2) then
print("Second sensor: "..t.read(addrs[2],t.K).."'K")
-- t:readTemp(readout) -- default pin value is 3
t:readTemp(readout, pin)
if t.sens then
print("Total number of DS18B20 sensors: "..table.getn(t.sens))
for i, s in ipairs(t.sens) do
-- print(string.format(" sensor #%d address: %s%s", i, s.addr, s.parasite == 1 and " (parasite)" or ""))
print(string.format(" sensor #%d address: %s%s", i, encoder.toHex(s.addr), s.parasite == 1 and " (parasite)" or "")) -- readable address with base64 encoding is preferred when encoder module is available
end
end
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
require('ds18b20')
t = require('ds18b20')
port = 80
pin = 3 -- gpio0 = 3, gpio2 = 4
gconn = {} -- global variable for connection
-- ESP-01 GPIO Mapping
gpio0, gpio2 = 3, 4
function readout(temp)
local resp = "HTTP/1.1 200 OK\nContent-Type: text/html\nRefresh: 5\n\n" ..
"<!DOCTYPE HTML>" ..
"<html><body>" ..
"<b>ESP8266</b></br>"
ds18b20.setup(gpio0)
for addr, temp in pairs(temp) do
-- resp = resp .. string.format("Sensor %s: %s &#8451</br>", addr, temp)
resp = resp .. string.format("Sensor %s: %s &#8451</br>", encoder.toHex(addr), temp) -- readable address with base64 encoding is preferred when encoder module is available
end
resp = resp ..
"Node ChipID: " .. node.chipid() .. "<br>" ..
"Node MAC: " .. wifi.sta.getmac() .. "<br>" ..
"Node Heap: " .. node.heap() .. "<br>" ..
"Timer Ticks: " .. tmr.now() .. "<br>" ..
"</html></body>"
gconn:send(resp)
gconn:on("sent",function(conn) conn:close() end)
end
srv=net.createServer(net.TCP)
srv:listen(port,
function(conn)
conn:send("HTTP/1.1 200 OK\nContent-Type: text/html\nRefresh: 5\n\n" ..
"<!DOCTYPE HTML>" ..
"<html><body>" ..
"<b>ESP8266</b></br>" ..
"Temperature : " .. ds18b20.read() .. "<br>" ..
"Node ChipID : " .. node.chipid() .. "<br>" ..
"Node MAC : " .. wifi.sta.getmac() .. "<br>" ..
"Node Heap : " .. node.heap() .. "<br>" ..
"Timer Ticks : " .. tmr.now() .. "<br>" ..
"</html></body>")
conn:on("sent",function(conn) conn:close() end)
gconn = conn
-- t:readTemp(readout) -- default pin value is 3
t:readTemp(readout, pin)
end
)
#DS18B20 Module
##Require
```lua
ds18b20 = require("ds18b20")
```
## Release
```lua
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
##Constant
C, F, K
<a id="ds18b20_setup"></a>
##setup()
####Description
Setting the pin of DS18B20.<br />
####Syntax
setup(pin)
####Parameters
pin: 1~10, IO index. If parameter is nil, it will use pin 9(GPIO2) automatically.<br />
####Returns
nil
####Example
```lua
ds18b20 = require("ds18b20")
ds18b20.setup(9)
-- Don't forget to release it after use
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####See also
**-** []()
<a id="ds18b20_addrs"></a>
## addrs()
####Description
Return a table contain all of the addresses of DS18B20 on one-wire. If the setup(pin) function not executed, the pin 9(GPIO2) will be initialized as one-wire mode automatically. <br />
####Syntax
addrs()
####Parameters
nil
####Returns
addrs: A table contain all of the addresses of DS18B20 on one-wire. Every address is a string. If failed, it will be nil. <br />
####Example
```lua
ds18b20 = require("ds18b20")
ds18b20.setup(9)
addrs = ds18b20.addrs()
if (addrs ~= nil) then
print("Total DS18B20 sensors: "..table.getn(addrs))
end
-- Don't forget to release it after use
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####See also
**-** []()
<a id="ds18b20_readNumber"></a>
## readNumber()
####Description
Read the value of temperature. If the setup(pin) function not executed, the pin 9(GPIO2) will be initialized as one-wire mode automatically. <br />
####Syntax
readNumber(addr, unit)
####Parameters
addr: string, the address of DS18B20. It will select the first address which be found when this parameter is nil.<br />
unit: integer, unit conversion. Only Constant is acceptable, such as C(Celsius),F(Fahrenheit) and K(Kelvin). If this parameter is nil, the constant C(Celsius) will be selected automatically. <br />
####Returns
t1: integer. The integer part of the temperature. If it read fails, return nil. <br />
t2: integer. The fractional part of the temperature. If it read fails, return nil. <br />
####Example
```lua
t=require("ds18b20")
t.setup(9)
addrs=t.addrs()
-- Total DS18B20 numbers, assume it is 2
print(table.getn(addrs))
-- The first DS18B20
print(t.readNumber(addrs[1],t.C))
print(t.readNumber(addrs[1],t.F))
print(t.readNumber(addrs[1],t.K))
-- The second DS18B20
print(t.readNumber(addrs[2],t.C))
print(t.readNumber(addrs[2],t.F))
print(t.readNumber(addrs[2],t.K))
-- Just read
print(t.readNumber())
-- Just read as fahrenheit
print(t.readNumber(nil,t.F))
-- Read as values
t1, t2 = t.readNumber()
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####See also
**-** []()
<a id="ds18b20_read"></a>
## read()
####Description
Read the string of temperature. If the setup(pin) function not executed, the pin 9(GPIO2) will be initialized as one-wire mode automatically. <br />
####Syntax
read(addr, unit)
####Parameters
addr: string, the address of DS18B20. It will select the first address which be found when this parameter is nil.<br />
unit: integer, unit conversion. Only Constant is acceptable, such as C(Celsius),F(Fahrenheit) and K(Kelvin). If this parameter is nil, the constant C(Celsius) will be selected automatically. <br />
####Returns
t: string. The string of the temperature. If it read fails, return nil.<br />
####Example
```lua
t=require("ds18b20")
t.setup(9)
addrs=t.addrs()
-- Total DS18B20 numbers, assume it is 2
print(table.getn(addrs))
-- The first DS18B20
print(t.read(addrs[1],t.C))
print(t.read(addrs[1],t.F))
print(t.read(addrs[1],t.K))
-- The second DS18B20
print(t.read(addrs[2],t.C))
print(t.read(addrs[2],t.F))
print(t.read(addrs[2],t.K))
-- Just read
print(t.read())
-- Just read as centigrade
print(t.read(nil,t.C))
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####See also
**-** []()
#DS18B20 模块
##引用
```lua
ds18b20 = require("ds18b20")
```
#释放
```lua
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
##常量
C, F, K
<a id="ds18b20_setup"></a>
##setup()
####描述
设置DS18B20所在的管脚(pin)。<br />
####语法
setup(pin)
####参数
pin: 1~10, IO 编号。如果参数为nil,会自动设定为9(GPIO2).<br />
####返回值
nil
####示例
```lua
ds18b20 = require("ds18b20")
ds18b20.setup(9)
-- Don't forget to release it after use
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####参见
**-** []()
<a id="ds18b20_addrs"></a>
## addrs()
####描述
返回单总线上所有DS18B20器件的地址列表(table)。如果没有执行过setup(pin),则会自动对引脚9(GPIO2)进行单总线模式初始化。<br />
####语法
addrs()
####参数
nil
####返回值
addrs: 返回包含单总线上所有DS18B20器件的地址列表(table)。其中地址是字符串类型(String)。如果失败则返回nil. <br />
####示例
```lua
ds18b20 = require("ds18b20")
ds18b20.setup(9)
addrs = ds18b20.addrs()
if (addrs ~= nil) then
print("Total DS18B20 sensors: "..table.getn(addrs))
end
-- Don't forget to release it after use
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####参见
**-** []()
<a id="ds18b20_readNumber"></a>
## readNumber()
####描述
读取温度数值。如果没有执行过setup(pin),则会自动对引脚9(GPIO2)进行单总线模式初始化。 <br />
####语法
readNumber(addr, unit)
####参数
addr: 字符串, DS18B20地址。 如果该参数为nil,会自动选择第一个发现的地址。<br />
unit: 单位转换,只接受常量C(摄氏度),F(华氏度), K(开氏度)。如果该参数为nil,会自动选择常量C(摄氏度) 。<br />
####返回值
t1: 数值,温度的整数部分。如果读取失败返回nil.<br />
t2: 数值,温度的小数部分。如果读取失败返回nil.<br />
####示例
```lua
t=require("ds18b20")
t.setup(9)
addrs=t.addrs()
-- Total DS18B20 numbers, assume it is 2
print(table.getn(addrs))
-- The first DS18B20
print(t.readNumber(addrs[1],t.C))
print(t.readNumber(addrs[1],t.F))
print(t.readNumber(addrs[1],t.K))
-- The second DS18B20
print(t.readNumber(addrs[2],t.C))
print(t.readNumber(addrs[2],t.F))
print(t.readNumber(addrs[2],t.K))
-- Just read
print(t.readNumber())
-- Just read as fahrenheit
print(t.readNumber(nil,t.F))
-- Read as values
t1, t2 = t.readNumber()
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####参见
**-** []()
<a id="ds18b20_read"></a>
## read()
####描述
读取温度字符串。如果没有执行过setup(pin),则会自动对引脚9(GPIO2)进行单总线模式初始化。 <br />
####语法
read(addr, unit)
####参数
addr: 字符串, DS18B20地址。 如果该参数为nil,会自动选择第一个发现的地址。<br />
unit: 单位转换,只接受常量C(摄氏度),F(华氏度), K(开氏度)。如果该参数为nil,会自动选择常量C(摄氏度) 。<br />
####返回值
t: 字符串,表示成字符串形式的温度。如果读取失败返回nil.<br />
####示例
```lua
t=require("ds18b20")
t.setup(9)
addrs=t.addrs()
-- Total DS18B20 numbers, assume it is 2
print(table.getn(addrs))
-- The first DS18B20
print(t.read(addrs[1],t.C))
print(t.read(addrs[1],t.F))
print(t.read(addrs[1],t.K))
-- The second DS18B20
print(t.read(addrs[2],t.C))
print(t.read(addrs[2],t.F))
print(t.read(addrs[2],t.K))
-- Just read
print(t.read())
-- Just read as centigrade
print(t.read(nil,t.C))
-- Don't forget to release it after use
t = nil
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
####参见
**-** []()
--------------------------------------------------------------------------------
-- DS18B20 one wire module for NODEMCU
-- NODEMCU TEAM
-- LICENCE: http://opensource.org/licenses/MIT
-- Vowstar <vowstar@nodemcu.com>
-- 2015/02/14 sza2 <sza2trash@gmail.com> Fix for negative values
-- by @voborsky, @devsaurus
-- encoder module is needed only for debug output; lines can be removed if no
-- debug output is needed and/or encoder module is missing
--
-- by default the module is for integer version, comment integer version and
-- uncomment float version part for float version
--------------------------------------------------------------------------------
-- Set module name as parameter of require
local modname = ...
local M = {}
_G[modname] = M
--------------------------------------------------------------------------------
-- Local used variables
--------------------------------------------------------------------------------
-- DS18B20 dq pin
local pin = nil
-- DS18B20 default pin
local defaultPin = 9
--------------------------------------------------------------------------------
-- Local used modules
--------------------------------------------------------------------------------
-- Table module
local table = table
-- String module
local string = string
-- One wire module
local ow = ow
-- Timer module
local tmr = tmr
-- Limited to local environment
setfenv(1,M)
--------------------------------------------------------------------------------
-- Implementation
--------------------------------------------------------------------------------
C = 'C'
F = 'F'
K = 'K'
function setup(dq)
pin = dq
if(pin == nil) then
pin = defaultPin
end
ow.setup(pin)
end
return({
pin=3,
sens={},
temp={},
function addrs()
setup(pin)
tbl = {}
ow.reset_search(pin)
repeat
addr = ow.search(pin)
if(addr ~= nil) then
table.insert(tbl, addr)
conversion = function(self)
local pin = self.pin
for i,s in ipairs(self.sens) do
if s.status == 0 then
print("starting conversion:", encoder.toHex(s.addr), s.parasite == 1 and "parasite" or " ")
ow.reset(pin)
ow.select(pin, s.addr) -- select the sensor
ow.write(pin, 0x44, 1) -- and start conversion
s.status = 1
if s.parasite == 1 then break end -- parasite sensor blocks bus during conversion
end
end
tmr.wdclr()
until (addr == nil)
ow.reset_search(pin)
return tbl
end
tmr.create():alarm(750, tmr.ALARM_SINGLE, function() self:readout() end)
end,
readTemp = function(self, cb, lpin)
if lpin then self.pin = lpin end
local pin = self.pin
self.cb = cb
self.temp={}
ow.setup(pin)
function readNumber(addr, unit)
result = nil
setup(pin)
flag = false
if(addr == nil) then
self.sens={}
ow.reset_search(pin)
count = 0
repeat
count = count + 1
-- ow.target_search(pin,0x28)
-- search the first device
local addr = ow.search(pin)
-- and loop through all devices
while addr do
-- search next device
local crc=ow.crc8(string.sub(addr,1,7))
if (crc==addr:byte(8)) and ((addr:byte(1)==0x10) or (addr:byte(1)==0x28)) then
ow.reset(pin)
ow.select(pin, addr) -- select the found sensor
ow.write(pin, 0xB4, 1) -- Read Power Supply [B4h]
local parasite = (ow.read(pin)==0 and 1 or 0)
table.insert(self.sens,{addr=addr, parasite=parasite, status=0})
print("contact: ", encoder.toHex(addr), parasite == 1 and "parasite" or " ")
end
addr = ow.search(pin)
tmr.wdclr()
until((addr ~= nil) or (count > 100))
ow.reset_search(pin)
end
if(addr == nil) then
return result
end
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.")
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)
if (t > 32767) then
t = t - 65536
end
-- place powered sensors first
table.sort(self.sens, function(a,b) return a.parasite<b.parasite end)
node.task.post(node.task.MEDIUM_PRIORITY, function() self:conversion() end)
end,
readout=function(self)
local pin = self.pin
local next = false
if not self.sens then return 0 end
for i,s in ipairs(self.sens) do
-- print(encoder.toHex(s.addr), s.status)
if s.status == 1 then
ow.reset(pin)
ow.select(pin, s.addr) -- select the sensor
ow.write(pin, 0xBE, 0) -- READ_SCRATCHPAD
data = ow.read_bytes(pin, 9)
local t=(data:byte(1)+data:byte(2)*256)
if (t > 0x7fff) then t = t - 0x10000 end
if (s.addr:byte(1) == 0x28) then
t = t * 625 -- DS18B20, 4 fractional bits
else
t = t * 5000 -- DS18S20, 1 fractional bit
end
if (addr:byte(1) == 0x28) then
t = t * 625 -- DS18B20, 4 fractional bits
else
t = t * 5000 -- DS18S20, 1 fractional bit
end
if 1/2 == 0 then
-- integer version
local sgn = t<0 and -1 or 1
local tA = sgn*t
local tH=tA/10000
local tL=(tA%10000)/1000 + ((tA%1000)/100 >= 5 and 1 or 0)
if(unit == nil or unit == 'C') then
-- do nothing
elseif(unit == 'F') then
t = t * 1.8 + 320000
elseif(unit == 'K') then
t = t + 2731500
if tH and (tH~=85) then
self.temp[s.addr]=(sgn<0 and "-" or "")..tH.."."..tL
print(encoder.toHex(s.addr),(sgn<0 and "-" or "")..tH.."."..tL)
s.status = 2
end
-- end integer version
else
return nil
-- float version
if t and (math.floor(t/10000)~=85) then
self.temp[s.addr]=t/10000
print(encoder.toHex(s.addr), t)
s.status = 2
end
-- end float version
end
t = t / 10000
return t
end
tmr.wdclr()
next = next or s.status == 0
end
if next then
node.task.post(node.task.MEDIUM_PRIORITY, function() self:conversion() end)
else
-- print("Device family is not recognized.")
self.sens = nil
if self.cb then
node.task.post(node.task.MEDIUM_PRIORITY, function() self.cb(self.temp) end)
end
end
else
-- print("CRC is not valid!")
end
return result
end
function read(addr, unit)
t = readNumber(addr, unit)
if (t == nil) then
return nil
else
return t
end
end
-- Return module table
return M
})
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment