diff --git a/lua_modules/ds18b20/ds18b20-example.lua b/lua_modules/ds18b20/ds18b20-example.lua
index c349e43a..d8ab621b 100644
--- a/lua_modules/ds18b20/ds18b20-example.lua
+++ b/lua_modules/ds18b20/ds18b20-example.lua
@@ -1,27 +1,26 @@
+-- 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.toBase64(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.toBase64(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
diff --git a/lua_modules/ds18b20/ds18b20-web.lua b/lua_modules/ds18b20/ds18b20-web.lua
index 7ff81979..41182dfd 100644
--- a/lua_modules/ds18b20/ds18b20-web.lua
+++ b/lua_modules/ds18b20/ds18b20-web.lua
@@ -1,27 +1,36 @@
-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" ..
+ "" ..
+ "
" ..
+ "ESP8266"
+
+ for addr, temp in pairs(temp) do
+ -- resp = resp .. string.format("Sensor %s: %s ℃", addr, temp)
+ resp = resp .. string.format("Sensor %s: %s ℃", encoder.toBase64(addr), temp) -- readable address with base64 encoding is preferred when encoder module is available
+ end
+
+ resp = resp ..
+ "Node ChipID: " .. node.chipid() .. "
" ..
+ "Node MAC: " .. wifi.sta.getmac() .. "
" ..
+ "Node Heap: " .. node.heap() .. "
" ..
+ "Timer Ticks: " .. tmr.now() .. "
" ..
+ ""
-ds18b20.setup(gpio0)
+ 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" ..
- "" ..
- "" ..
- "ESP8266" ..
- "Temperature : " .. ds18b20.read() .. "
" ..
- "Node ChipID : " .. node.chipid() .. "
" ..
- "Node MAC : " .. wifi.sta.getmac() .. "
" ..
- "Node Heap : " .. node.heap() .. "
" ..
- "Timer Ticks : " .. tmr.now() .. "
" ..
- "")
- conn:on("sent",function(conn) conn:close() end)
+ gconn = conn
+ -- t:readTemp(readout) -- default pin value is 3
+ t:readTemp(readout, pin)
end
)
-
-
diff --git a/lua_modules/ds18b20/ds18b20.EN.md b/lua_modules/ds18b20/ds18b20.EN.md
index bdf69397..155bc29d 100644
--- a/lua_modules/ds18b20/ds18b20.EN.md
+++ b/lua_modules/ds18b20/ds18b20.EN.md
@@ -8,150 +8,47 @@ ds18b20 = require("ds18b20")
ds18b20 = nil
package.loaded["ds18b20"]=nil
```
-##Constant
-C, F, K
-
-##setup()
-####Description
-Setting the pin of DS18B20.
+
+##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. Parasit-powered sensors are read one by one. The first parasit-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.toBase64()`).
####Syntax
-setup(pin)
+`readTemp(callback, pin)`
####Parameters
-pin: 1~10, IO index. If parameter is nil, it will use pin 9(GPIO2) automatically.
+- `callback` function that receives all results when all conversions finish. The callback funciton 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
-ds18b20 = require("ds18b20")
-ds18b20.setup(9)
--- Don't forget to release it after use
-ds18b20 = nil
-package.loaded["ds18b20"]=nil
-```
+t = require("ds18b20")
+pin = 3 -- gpio0 = 3, gpio2 = 4
-####See also
-**-** []()
+function readout(temp)
+ for addr, temp in pairs(temp) do
+ print(string.format("Sensor %s: %s 'C", encoder.toBase64(addr), temp))
+ end
-
-
-## 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.
-
-####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.
-
-####Example
-```lua
-ds18b20 = require("ds18b20")
-ds18b20.setup(9)
-addrs = ds18b20.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
+
+-- 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.toBase64(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
-ds18b20 = nil
-package.loaded["ds18b20"]=nil
```
-
-####See also
-**-** []()
-
-
-
-## 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.
-
-####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.
-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.
-
-####Returns
-t1: integer. The integer part of the temperature. If it read fails, return nil.
-t2: integer. The fractional part of the temperature. If it read fails, return nil.
-
-####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
-**-** []()
-
-
-## 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.
-
-####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.
-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.
-
-####Returns
-t: string. The string of the temperature. If it read fails, return nil.
-
-####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
-**-** []()
-
diff --git a/lua_modules/ds18b20/ds18b20.ZH.md b/lua_modules/ds18b20/ds18b20.ZH.md
deleted file mode 100644
index c6092714..00000000
--- a/lua_modules/ds18b20/ds18b20.ZH.md
+++ /dev/null
@@ -1,160 +0,0 @@
-#DS18B20 模块
-##引用
-```lua
-ds18b20 = require("ds18b20")
-```
-#释放
-```lua
-ds18b20 = nil
-package.loaded["ds18b20"]=nil
-```
-##常量
-C, F, K
-
-
-##setup()
-####描述
-设置DS18B20所在的管脚(pin)。
-
-####语法
-setup(pin)
-
-####参数
-pin: 1~10, IO 编号。如果参数为nil,会自动设定为9(GPIO2).
-
-####返回值
-nil
-
-####示例
-```lua
-ds18b20 = require("ds18b20")
-ds18b20.setup(9)
--- Don't forget to release it after use
-ds18b20 = nil
-package.loaded["ds18b20"]=nil
-
-```
-
-####参见
-**-** []()
-
-
-
-## addrs()
-####描述
-返回单总线上所有DS18B20器件的地址列表(table)。如果没有执行过setup(pin),则会自动对引脚9(GPIO2)进行单总线模式初始化。
-
-####语法
-addrs()
-
-####参数
-nil
-####返回值
-addrs: 返回包含单总线上所有DS18B20器件的地址列表(table)。其中地址是字符串类型(String)。如果失败则返回nil.
-
-####示例
-```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
-
-```
-
-####参见
-**-** []()
-
-
-
-## readNumber()
-####描述
-读取温度数值。如果没有执行过setup(pin),则会自动对引脚9(GPIO2)进行单总线模式初始化。
-
-####语法
-readNumber(addr, unit)
-
-####参数
-addr: 字符串, DS18B20地址。 如果该参数为nil,会自动选择第一个发现的地址。
-unit: 单位转换,只接受常量C(摄氏度),F(华氏度), K(开氏度)。如果该参数为nil,会自动选择常量C(摄氏度) 。
-
-####返回值
-t1: 数值,温度的整数部分。如果读取失败返回nil.
-t2: 数值,温度的小数部分。如果读取失败返回nil.
-
-####示例
-```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
-
-```
-####参见
-**-** []()
-
-
-## read()
-####描述
-读取温度字符串。如果没有执行过setup(pin),则会自动对引脚9(GPIO2)进行单总线模式初始化。
-
-####语法
-read(addr, unit)
-
-####参数
-addr: 字符串, DS18B20地址。 如果该参数为nil,会自动选择第一个发现的地址。
-unit: 单位转换,只接受常量C(摄氏度),F(华氏度), K(开氏度)。如果该参数为nil,会自动选择常量C(摄氏度) 。
-
-####返回值
-t: 字符串,表示成字符串形式的温度。如果读取失败返回nil.
-
-####示例
-```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
-```
-####参见
-**-** []()
-
diff --git a/lua_modules/ds18b20/ds18b20.lua b/lua_modules/ds18b20/ds18b20.lua
index de2d869b..7571ad39 100644
--- a/lua_modules/ds18b20/ds18b20.lua
+++ b/lua_modules/ds18b20/ds18b20.lua
@@ -1,143 +1,119 @@
--------------------------------------------------------------------------------
-- DS18B20 one wire module for NODEMCU
--- NODEMCU TEAM
--- LICENCE: http://opensource.org/licenses/MIT
--- Vowstar
--- 2015/02/14 sza2 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
-
-function addrs()
- setup(pin)
- tbl = {}
- ow.reset_search(pin)
- repeat
- addr = ow.search(pin)
- if(addr ~= nil) then
- table.insert(tbl, addr)
+return({
+ pin=3,
+ sens={},
+ temp={},
+
+ conversion = function(self)
+ local pin = self.pin
+ for i,s in ipairs(self.sens) do
+ if s.status == 0 then
+ print("starting conversion:", encoder.toBase64(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
-
-function readNumber(addr, unit)
- result = nil
- setup(pin)
- flag = false
- if(addr == nil) then
+ tmr.alarm(tmr.create(), 750, tmr.ALARM_SINGLE, function() self:readout() end)
+ end,
+
+ readTemp = function(self, cb, lpin)
+ local pin = self.pin
+ self.cb = cb
+ self.temp={}
+ if lpin then pin = lpin end
+ ow.setup(pin)
+
+ 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.toBase64(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
-
- if (addr:byte(1) == 0x28) then
- t = t * 625 -- DS18B20, 4 fractional bits
- else
- t = t * 5000 -- DS18S20, 1 fractional bit
- end
-
- 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
- else
- return nil
- end
- t = t / 10000
- return t
- end
- tmr.wdclr()
- else
- -- print("Device family is not recognized.")
end
- else
- -- print("CRC is not valid!")
- end
- return result
-end
+
+ -- place powered sensors first
+ table.sort(self.sens, function(a,b) return a.parasite 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
+
+ -- 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 tH and (tH~=85) then
+ self.temp[s.addr]=(sgn<0 and "-" or "")..tH.."."..tL
+ print(encoder.toBase64(s.addr),(sgn<0 and "-" or "")..tH.."."..tL)
+ s.status = 2
+ end
+ -- end integer version
+ -- -- float version
+ -- if t and (math.floor(t/10000)~=85) then
+ -- self.temp[s.addr]=t
+ -- print(encoder.toBase64(s.addr), t)
+ -- s.status = 2
+ -- end
+ -- -- end float version
+ end
+ next = next or s.status == 0
+ end
+ if next then
+ node.task.post(node.task.MEDIUM_PRIORITY, function() self:conversion() end)
+ else
+ self.sens = nil
+ if self.cb then
+ node.task.post(node.task.MEDIUM_PRIORITY, function() self.cb(self.temp) end)
+ end
+ end
+
end
-end
+})
--- Return module table
-return M