This commit is contained in:
Татьяна Фарбер 2026-03-08 16:03:33 +04:00
parent b07f1d53e9
commit a7a2dcbc7a
18 changed files with 1112 additions and 1 deletions

209
DS1820.lua Normal file
View File

@ -0,0 +1,209 @@
--------------------------------------------------------------------------------
-- DS18B20 one wire module for NODEMCU
-- NODEMCU TEAM
-- LICENCE: http://opensource.org/licenses/MIT
-- @voborsky, @devsaurus, TerryE 26 Mar 2017
--------------------------------------------------------------------------------
local modname = ...
-- Used modules and functions
local type, tostring, pcall, ipairs =
type, tostring, pcall, ipairs
-- Local functions
local ow_setup, ow_search, ow_select, ow_read, ow_read_bytes, ow_write, ow_crc8,
ow_reset, ow_reset_search, ow_skip, ow_depower =
ow.setup, ow.search, ow.select, ow.read, ow.read_bytes, ow.write, ow.crc8,
ow.reset, ow.reset_search, ow.skip, ow.depower
local node_task_post, node_task_LOW_PRIORITY = node.task.post, node.task.LOW_PRIORITY
local string_char, string_dump = string.char, string.dump
local now, tmr_create, tmr_ALARM_SINGLE = tmr.now, tmr.create, tmr.ALARM_SINGLE
local table_sort, table_concat = table.sort, table.concat
local file_open = file.open
local conversion
local DS18B20FAMILY = 0x28
local DS1920FAMILY = 0x10 -- and DS18S20 series
local CONVERT_T = 0x44
local READ_SCRATCHPAD = 0xBE
local READ_POWERSUPPLY= 0xB4
local MODE = 1
local pin, cb, unit = 3
local status = {}
local debugPrint = function() return end
--------------------------------------------------------------------------------
-- Implementation
--------------------------------------------------------------------------------
local function enable_debug()
debugPrint = function (...) print(now(),' ', ...) end
end
local function to_string(addr, esc)
if type(addr) == 'string' and #addr == 8 then
return ( esc == true and
'"\\%u\\%u\\%u\\%u\\%u\\%u\\%u\\%u"' or
'%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X '):format(addr:byte(1,8))
else
return tostring(addr)
end
end
local function readout(self)
local next = false
local sens = self.sens
local temp = self.temp
for i, s in ipairs(sens) do
if status[i] == 1 then
ow_reset(pin)
local addr = s:sub(1,8)
ow_select(pin, addr) -- select the sensor
ow_write(pin, READ_SCRATCHPAD, MODE)
local data = ow_read_bytes(pin, 9)
local t=(data:byte(1)+data:byte(2)*256)
-- t is actually signed so process the sign bit and adjust for fractional bits
-- the DS18B20 family has 4 fractional bits and the DS18S20s, 1 fractional bit
t = ((t <= 32767) and t or t - 65536) *
((addr:byte(1) == DS18B20FAMILY) and 625 or 5000)
local crc, b9 = ow_crc8(string.sub(data,1,8)), data:byte(9)
if unit == 'F' then
t = (t * 18)/10 + 320000
elseif unit == 'K' then
t = t + 2731500
end
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 (t~=850000) then
debugPrint(to_string(addr),(sgn<0 and "-" or "")..tH.."."..tL, crc, b9)
if crc==b9 then temp[addr]=t end
status[i] = 2
end
end
next = next or status[i] == 0
end
if next then
node_task_post(node_task_LOW_PRIORITY, function() return conversion(self) end)
else
--sens = {}
if cb then
node_task_post(node_task_LOW_PRIORITY, function() return cb(temp) end)
end
end
end
conversion = (function (self)
local sens = self.sens
local powered_only = true
for _, s in ipairs(sens) do powered_only = powered_only and s:byte(9) ~= 1 end
if powered_only then
debugPrint("starting conversion: all sensors")
ow_reset(pin)
ow_skip(pin) -- skip ROM selection, talk to all sensors
ow_write(pin, CONVERT_T, MODE) -- and start conversion
for i, _ in ipairs(sens) do status[i] = 1 end
else
local started = false
for i, s in ipairs(sens) do
if status[i] == 0 then
local addr, parasite = s:sub(1,8), s:byte(9) == 1
if parasite and started then break end -- do not start concurrent conversion of powered and parasite
debugPrint("starting conversion:", to_string(addr), parasite and "parasite" or "")
ow_reset(pin)
ow_select(pin, addr) -- select the sensor
ow_write(pin, CONVERT_T, MODE) -- and start conversion
status[i] = 1
if parasite then break end -- parasite sensor blocks bus during conversion
started = true
end
end
end
tmr_create():alarm(750, tmr_ALARM_SINGLE, function() return readout(self) end)
end)
local function _search(self, lcb, lpin, search, save)
self.temp = {}
if search then self.sens = {}; status = {} end
local sens = self.sens
pin = lpin or pin
local addr
if not search and #sens == 0 then
-- load addreses if available
debugPrint ("geting addreses from flash")
local s,check,a = pcall(dofile, "ds18b20_save.lc")
if s and check == "ds18b20" then
for i = 1, #a do sens[i] = a[i] end
end
debugPrint (#sens, "addreses found")
end
ow_setup(pin)
if search or #sens == 0 then
ow_reset_search(pin)
-- ow_target_search(pin,0x28)
-- search the first device
addr = ow_search(pin)
else
for i, _ in ipairs(sens) do status[i] = 0 end
end
local function cycle()
if addr then
local crc=ow_crc8(addr:sub(1,7))
if (crc==addr:byte(8)) and ((addr:byte(1)==DS1920FAMILY) or (addr:byte(1)==DS18B20FAMILY)) then
ow_reset(pin)
ow_select(pin, addr)
ow_write(pin, READ_POWERSUPPLY, MODE)
local parasite = (ow_read(pin)==0 and 1 or 0)
sens[#sens+1]= addr..string_char(parasite)
status[#sens] = 0
debugPrint("contact: ", to_string(addr), parasite == 1 and "parasite" or "")
end
addr = ow_search(pin)
node_task_post(node_task_LOW_PRIORITY, cycle)
else
ow_depower(pin)
-- place powered sensors first
table_sort(sens, function(a, b) return a:byte(9)<b:byte(9) end) -- parasite
-- save sensor addreses
if save then
debugPrint ("saving addreses to flash")
local addr_list = {}
for i =1, #sens do
local s = sens[i]
addr_list[i] = to_string(s:sub(1,8), true)..('.."\\%u"'):format(s:byte(9))
end
local save_statement = 'return "ds18b20", {' .. table_concat(addr_list, ',') .. '}'
debugPrint (save_statement)
local save_file = file_open("ds18b20_save.lc","w")
save_file:write(string_dump(loadstring(save_statement)))
save_file:close()
end
-- end save sensor addreses
if lcb then node_task_post(node_task_LOW_PRIORITY, lcb) end
end
end
cycle()
end
local function read_temp(self, lcb, lpin, lunit, force_search, save_search)
cb, unit = lcb, lunit or unit
_search(self, function() return conversion(self) end, lpin, force_search, save_search)
end
-- Set module name as parameter of require and return module table
local M = {
sens = {},
temp = {},
C = 'C', F = 'F', K = 'K',
read_temp = read_temp, enable_debug = enable_debug
}
_G[modname or 'ds18b20'] = M
return M

View File

@ -0,0 +1 @@
,zoviet,libreboot,30.03.2025 23:32,file:///home/zoviet/.config/libreoffice/4;

209
Ground/DS1820.lua Normal file
View File

@ -0,0 +1,209 @@
--------------------------------------------------------------------------------
-- DS18B20 one wire module for NODEMCU
-- NODEMCU TEAM
-- LICENCE: http://opensource.org/licenses/MIT
-- @voborsky, @devsaurus, TerryE 26 Mar 2017
--------------------------------------------------------------------------------
local modname = ...
-- Used modules and functions
local type, tostring, pcall, ipairs =
type, tostring, pcall, ipairs
-- Local functions
local ow_setup, ow_search, ow_select, ow_read, ow_read_bytes, ow_write, ow_crc8,
ow_reset, ow_reset_search, ow_skip, ow_depower =
ow.setup, ow.search, ow.select, ow.read, ow.read_bytes, ow.write, ow.crc8,
ow.reset, ow.reset_search, ow.skip, ow.depower
local node_task_post, node_task_LOW_PRIORITY = node.task.post, node.task.LOW_PRIORITY
local string_char, string_dump = string.char, string.dump
local now, tmr_create, tmr_ALARM_SINGLE = tmr.now, tmr.create, tmr.ALARM_SINGLE
local table_sort, table_concat = table.sort, table.concat
local file_open = file.open
local conversion
local DS18B20FAMILY = 0x28
local DS1920FAMILY = 0x10 -- and DS18S20 series
local CONVERT_T = 0x44
local READ_SCRATCHPAD = 0xBE
local READ_POWERSUPPLY= 0xB4
local MODE = 1
local pin, cb, unit = 3
local status = {}
local debugPrint = function() return end
--------------------------------------------------------------------------------
-- Implementation
--------------------------------------------------------------------------------
local function enable_debug()
debugPrint = function (...) print(now(),' ', ...) end
end
local function to_string(addr, esc)
if type(addr) == 'string' and #addr == 8 then
return ( esc == true and
'"\\%u\\%u\\%u\\%u\\%u\\%u\\%u\\%u"' or
'%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X '):format(addr:byte(1,8))
else
return tostring(addr)
end
end
local function readout(self)
local next = false
local sens = self.sens
local temp = self.temp
for i, s in ipairs(sens) do
if status[i] == 1 then
ow_reset(pin)
local addr = s:sub(1,8)
ow_select(pin, addr) -- select the sensor
ow_write(pin, READ_SCRATCHPAD, MODE)
local data = ow_read_bytes(pin, 9)
local t=(data:byte(1)+data:byte(2)*256)
-- t is actually signed so process the sign bit and adjust for fractional bits
-- the DS18B20 family has 4 fractional bits and the DS18S20s, 1 fractional bit
t = ((t <= 32767) and t or t - 65536) *
((addr:byte(1) == DS18B20FAMILY) and 625 or 5000)
local crc, b9 = ow_crc8(string.sub(data,1,8)), data:byte(9)
if unit == 'F' then
t = (t * 18)/10 + 320000
elseif unit == 'K' then
t = t + 2731500
end
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 (t~=850000) then
debugPrint(to_string(addr),(sgn<0 and "-" or "")..tH.."."..tL, crc, b9)
if crc==b9 then temp[addr]=t end
status[i] = 2
end
end
next = next or status[i] == 0
end
if next then
node_task_post(node_task_LOW_PRIORITY, function() return conversion(self) end)
else
--sens = {}
if cb then
node_task_post(node_task_LOW_PRIORITY, function() return cb(temp) end)
end
end
end
conversion = (function (self)
local sens = self.sens
local powered_only = true
for _, s in ipairs(sens) do powered_only = powered_only and s:byte(9) ~= 1 end
if powered_only then
debugPrint("starting conversion: all sensors")
ow_reset(pin)
ow_skip(pin) -- skip ROM selection, talk to all sensors
ow_write(pin, CONVERT_T, MODE) -- and start conversion
for i, _ in ipairs(sens) do status[i] = 1 end
else
local started = false
for i, s in ipairs(sens) do
if status[i] == 0 then
local addr, parasite = s:sub(1,8), s:byte(9) == 1
if parasite and started then break end -- do not start concurrent conversion of powered and parasite
debugPrint("starting conversion:", to_string(addr), parasite and "parasite" or "")
ow_reset(pin)
ow_select(pin, addr) -- select the sensor
ow_write(pin, CONVERT_T, MODE) -- and start conversion
status[i] = 1
if parasite then break end -- parasite sensor blocks bus during conversion
started = true
end
end
end
tmr_create():alarm(750, tmr_ALARM_SINGLE, function() return readout(self) end)
end)
local function _search(self, lcb, lpin, search, save)
self.temp = {}
if search then self.sens = {}; status = {} end
local sens = self.sens
pin = lpin or pin
local addr
if not search and #sens == 0 then
-- load addreses if available
debugPrint ("geting addreses from flash")
local s,check,a = pcall(dofile, "ds18b20_save.lc")
if s and check == "ds18b20" then
for i = 1, #a do sens[i] = a[i] end
end
debugPrint (#sens, "addreses found")
end
ow_setup(pin)
if search or #sens == 0 then
ow_reset_search(pin)
-- ow_target_search(pin,0x28)
-- search the first device
addr = ow_search(pin)
else
for i, _ in ipairs(sens) do status[i] = 0 end
end
local function cycle()
if addr then
local crc=ow_crc8(addr:sub(1,7))
if (crc==addr:byte(8)) and ((addr:byte(1)==DS1920FAMILY) or (addr:byte(1)==DS18B20FAMILY)) then
ow_reset(pin)
ow_select(pin, addr)
ow_write(pin, READ_POWERSUPPLY, MODE)
local parasite = (ow_read(pin)==0 and 1 or 0)
sens[#sens+1]= addr..string_char(parasite)
status[#sens] = 0
debugPrint("contact: ", to_string(addr), parasite == 1 and "parasite" or "")
end
addr = ow_search(pin)
node_task_post(node_task_LOW_PRIORITY, cycle)
else
ow_depower(pin)
-- place powered sensors first
table_sort(sens, function(a, b) return a:byte(9)<b:byte(9) end) -- parasite
-- save sensor addreses
if save then
debugPrint ("saving addreses to flash")
local addr_list = {}
for i =1, #sens do
local s = sens[i]
addr_list[i] = to_string(s:sub(1,8), true)..('.."\\%u"'):format(s:byte(9))
end
local save_statement = 'return "ds18b20", {' .. table_concat(addr_list, ',') .. '}'
debugPrint (save_statement)
local save_file = file_open("ds18b20_save.lc","w")
save_file:write(string_dump(loadstring(save_statement)))
save_file:close()
end
-- end save sensor addreses
if lcb then node_task_post(node_task_LOW_PRIORITY, lcb) end
end
end
cycle()
end
local function read_temp(self, lcb, lpin, lunit, force_search, save_search)
cb, unit = lcb, lunit or unit
_search(self, function() return conversion(self) end, lpin, force_search, save_search)
end
-- Set module name as parameter of require and return module table
local M = {
sens = {},
temp = {},
C = 'C', F = 'F', K = 'K',
read_temp = read_temp, enable_debug = enable_debug
}
_G[modname or 'ds18b20'] = M
return M

2
Ground/flash.sh Normal file
View File

@ -0,0 +1,2 @@
python3 -m esptool --port /dev/ttyUSB0 erase_flash
python3 -m esptool --port /dev/ttyUSB0 write_flash -fm dio 0x00000 nodemcu-release-9-modules-2024-09-15-16-23-23-integer.bin

43
Ground/init.lua Normal file
View File

@ -0,0 +1,43 @@
local t = require("DS1820")
local pin = 1
function adc_read()
local ao = adc.read(0)
print(ao)
end
local function readout(temp)
if t.sens then
print("Total number of DS18B20 sensors: ".. #t.sens)
for i, s in ipairs(t.sens) do
print(string.format(" sensor #%d address: %s%s", i, ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(s:byte(1,8)), s:byte(9) == 1 and " (parasite)" or ""))
end
end
for addr, temp in pairs(temp) do
--if tonumber(temp) < 20000 then
print(string.format("Sensor %s: %s °C", ('%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'):format(addr:byte(1,8)), temp))
--end
end
-- Module can be released when it is no longer needed
--t = nil
--package.loaded["ds18b20"] = nil
end
local function read()
t:read_temp(readout, pin, t.C)
end
if adc.force_init_mode(adc.INIT_ADC)
then
node.restart()
return -- don't bother continuing, the restart is scheduled
end
timer = tmr.create()
timer:register(7000, tmr.ALARM_AUTO,read)
timer:start()
sensorstimer = tmr.create()
sensorstimer:register(5000, tmr.ALARM_AUTO, adc_read)
sensorstimer:start()

BIN
Ground/датчики.ods Normal file

Binary file not shown.

View File

@ -1,2 +1,76 @@
# braga_firmware # Бродильная камера на ESP 8266
## Необходимые детали
1. Wemos D1 Mini
2. Датчик интенсивности ультрафиолета GUVA-S12SD
3. Датчик температуры и влажности DHT-11
4. Датчик давления и температуры BMP280
## Схема подключения
DHT 11:
"-" - GND
S - D1
V - 3.3
BME280:
SDA - D3
SCL - D4
G - G
V - 3.3
GUVA-S12SD:
SIO - AO
GND - G
VCC - 3.3
## Прошивка
Понадобятся:
1. esptool - https://docs.espressif.com/projects/esptool/en/latest/esp32/
2. git
3. python2 и python3
По желанию ESPlorer - https://esp8266.ru/forum/threads/esplorer.34/
Загрузка прошивки с необходимыми модулями:
```
git clone https://github.com/Zoviet/meteo
cd meteo
bash flash.sh
```
После загрузки прошивки устройство сразу готово к работе.
## Подключение к Wi-Fi
При подключении к новой сети устройство поднимает веб-сервер. В списке доступных Wi-Fi сетей появится сеть meteo, к которой следует подключиться. В запросе авторизации появится форма для выбора сети, к которой планируется подключить устройство, и форма ввода пароля от нее.
## Проверка работособности
При включении и/или перезагрузке устройство, даже не подключенное к Интернету, отдает в виртуальный COM-порт данные датчиков. Прочитать из можно с помощью ESPlorer либо любой программы для чтения COM-порта.
## Протокол обмена с сервером
TCP, порт 4999, ожидаемый формат - json, закодированный в Base64.

BIN
Schematic/schematic.fzz Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

3
firmware.sh Normal file
View File

@ -0,0 +1,3 @@
dmesg | grep tty
python3 -m esptool --port /dev/ttyUSB0 erase_flash
python3 -m esptool --port /dev/ttyUSB0 write_flash -fm dio 0x00000 nodemcu-release-17-modules-2025-01-01-15-13-22-float.bin

66
flash.sh Executable file
View File

@ -0,0 +1,66 @@
#!/bin/bash
if read -p "Подключите плату к USB и нажмите ENTER: " start; then
line=$(dmesg | grep 'ttyUSB' | tail -1)
if [[ $line == *"attached"* ]]; then
port=`echo "$line" | sed 's/.*ttyUSB\(.\)$/\1/'`
else
printf '\033[91mУстройство не найдено!\033[0m\n'
exit 0
fi
printf '\033[92mУстройство найдено на порту: '$port'\033[0m\n'
fi
if read -p "Для начала прошивки нажмите ENTER: " start; then
cd Firmware
firmware=($(find -name '*.bin'))
if [[ $firmware == *"nodemcu"* ]]; then
printf '\033[92mНайдена прошивка: '$firmware'\033[0m\n\n'
printf '\n\033[92mСтираем существующую прошивку:\033[0m\n\n'
python3 -m esptool --port /dev/ttyUSB$port erase_flash
if [ $? -ne 0 ]; then
printf '\033[91mОшибка устройства!\033[0m\n'
exit 0
fi
printf '\n\033[92mЗаливаем прошивку nodemcu для Lua:\033[0m\n\n'
python3 -m esptool --port /dev/ttyUSB$port write_flash -fm dio 0x00000 $firmware
if [ $? -ne 0 ]; then
printf '\033[91mОшибка устройства!\033[0m\n'
exit 0
fi
else
printf '\033[91mПрошивка не найдена!\033[0m\n'
exit 0
fi
fi
cd ../
if read -p "Для начала заливки скетча нажмите ENTER: " start; then
echo 'Заливаем Lua скетч:'
python2 luatool.py --port /dev/ttyUSB$port --src init.lua --dest init.lua --verbose --restart --baud 115200
if [ $? -ne 0 ]; then
printf '\033[91mОшибка заливки скетча!\033[0m\n'
exit 0
fi
fi
printf '\n\033[92mЖдем перезагрузки устройства:\033[0m\n\n'
sleep 5
mac=$(python3 -m esptool --port /dev/ttyUSB$port read_mac)
if [ $? -ne 0 ]; then
printf '\033[91mОшибка чтения из устройства!\033[0m\n'
exit 0
fi
guid=`echo "$mac" | grep -m 1 MAC | sed 's/\://g' | sed 's/MAC //g'`
echo 'GUID устройства: '$guid
first_byte=${guid:0:2}
new_byte=$((16#$first_byte + 2 | bc))
new_first_byte=`echo "ibase=10; obase=16; ${new_byte}" | bc | sed 's/[A-Z]/\L&/g'`
if (( ${#new_first_byte} == 1 )); then
new_first_byte='0'$new_first_byte
fi
guid=`echo "$guid" | sed 's/^'$first_byte'/'$new_first_byte'/'`
printf '\033[92mОпределен guid устройства: '$guid' \033[0m\n'
printf '\033[92mУстановка успешно завершена, ID устройства: \033[0m'$guid'\n'

129
init.lua Normal file
View File

@ -0,0 +1,129 @@
timing = 5000 -- Sending timer
srv = nil -- TCP client
uid = '' -- MAC UID
dhtpin = 1 -- DHT11 pin
sda, scl = 3, 4 -- BME280 pins
alt = 320 -- altitude of the measurement place
-- Weather vars
T = - 300 -- BME temp
P = - 300 -- BME pressure
curAlt = - 300 -- BME altitude
TB = - 300 -- DHT temp
TH = - 300 -- DHT humidity
UF = 0 -- UF index
-- Read the solar sensor
function adc_read()
UF = adc.read(0)
print('UF index: '..UF)
end
-- Read the BME280 sensor
function bme_read()
T, P, H, QNH = bme280.read(alt)
local Tsgn = (T < 0 and -1 or 1); T = Tsgn*T
print(string.format("T=%s%d.%02d", Tsgn<0 and "-" or "", T/100, T%100))
print(string.format("QFE=%d.%03d", P/1000, P%1000))
print(string.format("QNH=%d.%03d", QNH/1000, QNH%1000))
P = bme280.baro()
curAlt = bme280.altitude(P, QNH)
local curAltsgn = (curAlt < 0 and -1 or 1); curAlt = curAltsgn*curAlt
print(string.format("altitude=%s%d.%02d", curAltsgn<0 and "-" or "", curAlt/100, curAlt%100))
end
-- Read the DHT11 sensor
function dht_read()
status, temp, humi, temp_dec, humi_dec = dht.read(dhtpin)
if status == dht.OK then
TB = temp
TH = humi
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
end
-- Prepare data for TCP server
function data_out()
local pack = {}
pack['id'] = uid
pack['bme'] = {['temp'] = T,['press'] = P,['alt'] = curAlt}
pack['dht'] = {['temp'] = TB,['humi'] = TH}
pack['uf'] = UF
return encoder.toBase64(sjson.encode(pack))
end
-- Exchange data with server
function tcp()
srv:connect(4999,"braga.ulgrad.ru")
srv:on("connection", function(sck, c)
print('connection')
sck:send(data_out().."\r\n")
end)
srv:on("disconnection", function(sck,c)
print('disconnection')
end)
end
-- On Internet connect
function on_connect()
-- Generate UID from MAC address
uid = string.gsub(wifi.ap.getmac(),':','')
print("Connected to wifi as: " .. wifi.sta.getip())
ssid,password,bssid_set,bssid = wifi.sta.getconfig()
sensor_start()
print(
"\nCurrent Station configuration:"
.."\nSSID : "..ssid
.."\nPassword : "..password
.."\nBSSID_set : "..bssid_set
.."\nBSSID: "..bssid
.."\nUID:"..uid
.."\nClient IP:"..wifi.sta.getip().."\n"
)
srv = net.createConnection(net.TCP, 0)
if srv then
print('TCP Connection start')
tcptimer:start()
else
print('Error connect to TCP')
end
end
-- Setup ADC
if adc.force_init_mode(adc.INIT_ADC)
then
node.restart()
return -- don't bother continuing, the restart is scheduled
end
-- Setup sensors
i2c.setup(0, sda, scl, i2c.SLOW) -- call i2c.setup() only once
bme280.setup()
-- Setup timers
tcptimer = tmr.create()
tcptimer:register(12000, tmr.ALARM_AUTO,tcp)
inittimer = tmr.create()
inittimer:register(5000, tmr.ALARM_SINGLE, function()
adc_read()
bme_read()
dht_read()
enduser_setup.start('meteo',on_connect)
end)
inittimer:start()

358
luatool.py Executable file
View File

@ -0,0 +1,358 @@
#!/usr/bin/env python2
#
# ESP8266 luatool
# Author e-mail: 4ref0nt@gmail.com
# Site: http://esp8266.ru
# Contributions from: https://github.com/sej7278
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
# Street, Fifth Floor, Boston, MA 02110-1301 USA.
import sys
import serial
from time import sleep
import socket
import argparse
from os.path import basename
tqdm_installed = True
try:
from tqdm import tqdm
except ImportError, e:
if e.message == 'No module named tqdm':
tqdm_installed = False
else:
raise
version = "0.6.4"
class TransportError(Exception):
"""Custom exception to represent errors with a transport
"""
def __init__(self, message):
self.message = message
def __str__(self):
return self.message
class AbstractTransport:
def __init__(self):
raise NotImplementedError('abstract transports cannot be instantiated.')
def close(self):
raise NotImplementedError('Function not implemented')
def read(self, length):
raise NotImplementedError('Function not implemented')
def writeln(self, data, check=1):
raise NotImplementedError('Function not implemented')
def writer(self, data):
self.writeln("file.writeline([==[" + data + "]==])\r")
def performcheck(self, expected):
line = ''
char = ''
i = -1
while char != chr(62): # '>'
char = self.read(1)
if char == '':
raise Exception('No proper answer from MCU')
if char == chr(13) or char == chr(10): # LF or CR
if line != '':
line = line.strip()
if line+'\r' == expected and not args.bar:
sys.stdout.write(" -> ok")
elif line+'\r' != expected:
if line[:4] == "lua:":
sys.stdout.write("\r\n\r\nLua ERROR: %s" % line)
raise Exception('ERROR from Lua interpreter\r\n\r\n')
else:
expected = expected.split("\r")[0]
sys.stdout.write("\r\n\r\nERROR")
sys.stdout.write("\r\n send string : '%s'" % expected)
sys.stdout.write("\r\n expected echo : '%s'" % expected)
sys.stdout.write("\r\n but got answer : '%s'" % line)
sys.stdout.write("\r\n\r\n")
raise Exception('Error sending data to MCU\r\n\r\n')
line = ''
else:
line += char
if char == chr(62) and expected[i] == char:
char = ''
i += 1
class SerialTransport(AbstractTransport):
def __init__(self, port, baud, delay):
self.port = port
self.baud = baud
self.serial = None
self.delay = delay
try:
self.serial = serial.Serial(port, baud)
except serial.SerialException as e:
raise TransportError(e.strerror)
self.serial.timeout = 3
self.serial.interCharTimeout = 3
def writeln(self, data, check=1):
if self.serial.inWaiting() > 0:
self.serial.flushInput()
if len(data) > 0 and not args.bar:
sys.stdout.write("\r\n->")
sys.stdout.write(data.split("\r")[0])
self.serial.write(data)
sleep(self.delay)
if check > 0:
self.performcheck(data)
elif not args.bar:
sys.stdout.write(" -> send without check")
def read(self, length):
return self.serial.read(length)
def close(self):
self.serial.flush()
self.serial.close()
class TcpSocketTransport(AbstractTransport):
def __init__(self, host, port):
self.host = host
self.port = port
self.socket = None
try:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error as e:
raise TransportError(e.strerror)
try:
self.socket.connect((host, port))
except socket.error as e:
raise TransportError(e.strerror)
# read intro from telnet server (see telnet_srv.lua)
self.socket.recv(50)
def writeln(self, data, check=1):
if len(data) > 0 and not args.bar:
sys.stdout.write("\r\n->")
sys.stdout.write(data.split("\r")[0])
self.socket.sendall(data)
if check > 0:
self.performcheck(data)
elif not args.bar:
sys.stdout.write(" -> send without check")
def read(self, length):
return self.socket.recv(length)
def close(self):
self.socket.close()
def decidetransport(cliargs):
if cliargs.ip:
data = cliargs.ip.split(':')
host = data[0]
if len(data) == 2:
port = int(data[1])
else:
port = 23
return TcpSocketTransport(host, port)
else:
return SerialTransport(cliargs.port, cliargs.baud, cliargs.delay)
if __name__ == '__main__':
# parse arguments or use defaults
parser = argparse.ArgumentParser(description='ESP8266 Lua script uploader.')
parser.add_argument('-p', '--port', default='/dev/ttyUSB0', help='Device name, default /dev/ttyUSB0')
parser.add_argument('-b', '--baud', default=9600, help='Baudrate, default 9600')
parser.add_argument('-f', '--src', default='main.lua', help='Source file on computer, default main.lua')
parser.add_argument('-t', '--dest', default=None, help='Destination file on MCU, default to source file name')
parser.add_argument('-c', '--compile', action='store_true', help='Compile lua to lc after upload')
parser.add_argument('-r', '--restart', action='store_true', help='Restart MCU after upload')
parser.add_argument('-d', '--dofile', action='store_true', help='Run the Lua script after upload')
parser.add_argument('-v', '--verbose', action='store_true', help="Show progress messages.")
parser.add_argument('-a', '--append', action='store_true', help='Append source file to destination file.')
parser.add_argument('-l', '--list', action='store_true', help='List files on device')
parser.add_argument('-w', '--wipe', action='store_true', help='Delete all lua/lc files on device.')
parser.add_argument('-i', '--id', action='store_true', help='Query the modules chip id.')
parser.add_argument('-e', '--echo', action='store_true', help='Echo output of MCU until script is terminated.')
parser.add_argument('--bar', action='store_true', help='Show a progress bar for uploads instead of printing each line')
parser.add_argument('--delay', default=0.3, help='Delay in seconds between each write.', type=float)
parser.add_argument('--delete', default=None, help='Delete a lua/lc file from device.')
parser.add_argument('--ip', default=None, help='Connect to a telnet server on the device (--ip IP[:port])')
args = parser.parse_args()
transport = decidetransport(args)
if args.bar and not tqdm_installed:
sys.stdout.write("You must install the tqdm library to use the bar feature\n")
sys.stdout.write("To install, at the prompt type: \"pip install tqdm\"\n")
sys.exit(0)
if args.list:
transport.writeln("local l = file.list();for k,v in pairs(l) do print('name:'..k..', size:'..v)end\r", 0)
while True:
char = transport.read(1)
if char == '' or char == chr(62):
break
sys.stdout.write(char)
sys.exit(0)
if args.id:
transport.writeln("=node.chipid()\r", 0)
id=""
while True:
char = transport.read(1)
if char == '' or char == chr(62):
break
if char.isdigit():
id += char
print("\n"+id)
sys.exit(0)
if args.wipe:
transport.writeln("local l = file.list();for k,v in pairs(l) do print(k)end\r", 0)
file_list = []
fn = ""
while True:
char = transport.read(1)
if char == '' or char == chr(62):
break
if char not in ['\r', '\n']:
fn += char
else:
if fn:
file_list.append(fn.strip())
fn = ''
for fn in file_list[1:]: # first line is the list command sent to device
if args.verbose:
sys.stderr.write("Delete file {} from device.\r\n".format(fn))
transport.writeln("file.remove(\"" + fn + "\")\r")
sys.exit(0)
if args.delete:
transport.writeln("file.remove(\"" + args.delete + "\")\r")
sys.exit(0)
if args.dest is None:
args.dest = basename(args.src)
# open source file for reading
try:
try:
f = open(args.src, "rt")
except:
import os
base_dir = os.path.dirname(os.path.realpath(__file__))
f = open(os.path.join(base_dir, args.src), "rt")
os.chdir(base_dir)
except:
sys.stderr.write("Could not open input file \"%s\"\n" % args.src)
sys.exit(1)
# Verify the selected file will not exceed the size of the serial buffer.
# The size of the buffer is 256. This script does not accept files with
# lines longer than 230 characters to have some room for command overhead.
num_lines = 0
for ln in f:
if len(ln) > 230:
sys.stderr.write("File \"%s\" contains a line with more than 240 "
"characters. This exceeds the size of the serial buffer.\n"
% args.src)
f.close()
sys.exit(1)
num_lines += 1
# Go back to the beginning of the file after verifying it has the correct
# line length
f.seek(0)
# set serial timeout
if args.verbose:
sys.stderr.write("Upload starting\r\n")
# remove existing file on device
if args.append==False:
if args.verbose:
sys.stderr.write("Stage 1. Deleting old file from flash memory")
transport.writeln("file.open(\"" + args.dest + "\", \"w\")\r")
transport.writeln("file.close()\r")
transport.writeln("file.remove(\"" + args.dest + "\")\r")
else:
if args.verbose:
sys.stderr.write("[SKIPPED] Stage 1. Deleting old file from flash memory [SKIPPED]")
# read source file line by line and write to device
if args.verbose:
sys.stderr.write("\r\nStage 2. Creating file in flash memory and write first line")
if args.append:
transport.writeln("file.open(\"" + args.dest + "\", \"a+\")\r")
else:
transport.writeln("file.open(\"" + args.dest + "\", \"w+\")\r")
line = f.readline()
if args.verbose:
sys.stderr.write("\r\nStage 3. Start writing data to flash memory...")
if args.bar:
for i in tqdm(range(0, num_lines)):
transport.writer(line.strip())
line = f.readline()
else:
while line != '':
transport.writer(line.strip())
line = f.readline()
# close both files
f.close()
if args.verbose:
sys.stderr.write("\r\nStage 4. Flush data and closing file")
transport.writeln("file.flush()\r")
transport.writeln("file.close()\r")
# compile?
if args.compile:
if args.verbose:
sys.stderr.write("\r\nStage 5. Compiling")
transport.writeln("node.compile(\"" + args.dest + "\")\r")
transport.writeln("file.remove(\"" + args.dest + "\")\r")
# restart or dofile
if args.restart:
transport.writeln("node.restart()\r")
if args.dofile: # never exec if restart=1
transport.writeln("dofile(\"" + args.dest + "\")\r", 0)
if args.echo:
if args.verbose:
sys.stderr.write("\r\nEchoing MCU output, press Ctrl-C to exit")
while True:
sys.stdout.write(transport.read(1))
# close serial port
transport.close()
# flush screen
sys.stdout.flush()
sys.stderr.flush()
if not args.bar:
sys.stderr.write("\r\n--->>> All done <<<---\r\n")

15
tests/client.lua Normal file
View File

@ -0,0 +1,15 @@
local host, port = "meteo.ulgrad.ru", 4999
local socket = require("socket")
local tcp = assert(socket.tcp())
tcp:connect(host, port);
--note the newline below
tcp:send("thunder!");
while true do
local s, status, partial = tcp:receive()
print(s or partial)
print(status)
if status == "closed" then break end
end
tcp:close()

2
tests/tcp.test Normal file
View File

@ -0,0 +1,2 @@
nc meteo.ulgrad.ru 4999
nc 5.187.7.142 4999