179 lines
4.1 KiB
Markdown
179 lines
4.1 KiB
Markdown
# si7021d
|
|
|
|
This is a Linux daemon that reads and returns data from a Si-7021 sensor. It's written
|
|
on Python, uses asyncio and was tested on Python 3.9.
|
|
|
|
It starts TCP server, accepts command `read` and returns JSON with sensor readings.
|
|
You can send as many `read` commands during one connection as you want.
|
|
|
|
## Why?
|
|
|
|
It was created for AwesomeWM widget. The daemon is running on some Orange Pi board
|
|
with Si7021 sensor attached, the widget periodically pings it and draws temperature
|
|
and relative humidity on a wibox.
|
|
|
|
Sample widget code:
|
|
```lua
|
|
local wibox = require("wibox")
|
|
local gears = require('gears')
|
|
local awful = require("awful")
|
|
local naughty = require("naughty")
|
|
local theme = require("./themes/default/theme")
|
|
local json = require('json')
|
|
local util = require('./util')
|
|
local lgi = require('lgi')
|
|
local Gio = lgi.Gio
|
|
|
|
local SI7021_IP = '192.168.1.212'
|
|
local SI7021_PORT = 8306
|
|
local UPDATE_FREQUENCY = 2
|
|
|
|
local timer
|
|
local timer_started = false
|
|
|
|
|
|
-----------------
|
|
-- widgets stuff
|
|
|
|
local function create_image(file)
|
|
image_widget = wibox.widget.imagebox()
|
|
image_widget:set_resize(false)
|
|
image_widget:set_image(file)
|
|
return image_widget
|
|
end
|
|
|
|
local function wrap_image(image, top)
|
|
margin = wibox.container.margin()
|
|
margin:set_left(16)
|
|
margin:set_top(top)
|
|
margin:set_right(5)
|
|
margin:set_widget(image)
|
|
return margin
|
|
end
|
|
|
|
local function create_text(placeholder)
|
|
text_widget = wibox.widget.textbox()
|
|
text_widget:set_font(theme.font)
|
|
if placeholder then
|
|
text_widget:set_text(placeholder)
|
|
end
|
|
return text_widget
|
|
end
|
|
|
|
|
|
local temp_image = create_image(awful.util.getdir("config") .. "/icons/fs_01.png")
|
|
local temp_text = create_text('Connecting...')
|
|
local temp_image_wrapped = wrap_image(temp_image, 8)
|
|
|
|
local hum_image = create_image(awful.util.getdir("config") .. "/icons/humidity.png")
|
|
local hum_text = create_text()
|
|
local hum_image_wrapped = wrap_image(hum_image, 7)
|
|
|
|
local layout = wibox.layout.fixed.horizontal()
|
|
layout:add(temp_image_wrapped)
|
|
layout:add(temp_text)
|
|
|
|
local hum_visible = false
|
|
local function hum_hide()
|
|
if not hum_visible then return end
|
|
layout:remove_widgets(hum_image_wrapped)
|
|
layout:remove_widgets(hum_text)
|
|
hum_visible = false
|
|
end
|
|
|
|
local function hum_show()
|
|
if hum_visible then return end
|
|
layout:add(hum_image_wrapped)
|
|
layout:add(hum_text)
|
|
hum_visible = true
|
|
end
|
|
|
|
|
|
--------------------
|
|
--- networking stuff
|
|
|
|
local _socket
|
|
local _tcp_conn
|
|
local _istream
|
|
local _ostream
|
|
|
|
local function sensor_get_status()
|
|
_istream = _tcp_conn:get_input_stream()
|
|
_ostream = _tcp_conn:get_output_stream()
|
|
|
|
_ostream:async_write("read\r\n")
|
|
|
|
local buf = ''
|
|
while true do
|
|
local bytes = _istream:async_read_bytes(4096)
|
|
|
|
-- it returns nil on error (such as disconnect)
|
|
if bytes == nil then return nil end
|
|
if not bytes then break end
|
|
|
|
local len = bytes:get_size()
|
|
if len > 0 then
|
|
buf = bytes.data
|
|
break
|
|
end
|
|
end
|
|
|
|
return true, buf
|
|
end
|
|
|
|
local function sensor_update()
|
|
Gio.Async.start(function()
|
|
local ok, body = sensor_get_status()
|
|
|
|
-- handle errors
|
|
if ok == nil then
|
|
temp_text:set_text("Connection error")
|
|
hum_hide()
|
|
|
|
_socket = nil
|
|
|
|
timer:stop()
|
|
timer_started = false
|
|
|
|
return
|
|
end
|
|
|
|
local status = json.decode(body)
|
|
|
|
hum_show()
|
|
temp_text:set_text('' .. util.round(status.temp, 1) .. ' °C')
|
|
hum_text:set_text('' .. util.round(status.humidity, 1) .. ' %')
|
|
end)()
|
|
end
|
|
|
|
local function sensor_connect()
|
|
_socket = Gio.SocketClient.new()
|
|
_socket:set_timeout(1)
|
|
|
|
_tcp_conn = _socket:async_connect_to_host(SI7021_IP, SI7021_PORT)
|
|
|
|
if not _tcp_conn then
|
|
_socket = nil
|
|
temp_text:set_text('Connection error')
|
|
return
|
|
end
|
|
|
|
timer = gears.timer({ timeout = UPDATE_FREQUENCY })
|
|
timer:connect_signal("timeout", sensor_update)
|
|
|
|
timer:start()
|
|
timer_started = true
|
|
|
|
sensor_update()
|
|
end
|
|
|
|
|
|
Gio.Async.start(sensor_connect)()
|
|
|
|
return layout
|
|
```
|
|
|
|
## License
|
|
|
|
MIT
|