diff options
-rwxr-xr-x | files/common/openwrt/sensors-init.lua | 77 | ||||
-rw-r--r-- | files/common/openwrt/sensors.module_lua | 173 | ||||
-rw-r--r-- | inventory/group_vars/chaos-at-home-sensors/vars.yml | 33 | ||||
-rw-r--r-- | inventory/host_vars/ch-sensors1.yml | 19 |
4 files changed, 215 insertions, 87 deletions
diff --git a/files/common/openwrt/sensors-init.lua b/files/common/openwrt/sensors-init.lua index f958dd2d..a283bfc7 100755 --- a/files/common/openwrt/sensors-init.lua +++ b/files/common/openwrt/sensors-init.lua @@ -1,75 +1,10 @@ #!/usr/bin/lua -cjson = require "cjson.safe" -glob = require "posix.glob" -time = require "posix.time" -unistd = require "posix.unistd" +local sensors = require "sensors" --- ############# utils ########### +local config, err = sensors.read_config('/etc/sensors.json') +if not config then error(err) end -function i2c_bus_path(bus) - return string.format("/sys/bus/i2c/devices/i2c-%d", bus) -end - -function i2c_device_path(bus, address) - return string.format("/sys/bus/i2c/devices/%d-%04X", bus, address) -end - -function i2c_add_device(bus, name, address) - local f, err = io.open(i2c_bus_path(bus) .. "/new_device", "w") - if not f then return nil, err end - - ret, err = f:write(string.format("%s 0x%02X", name, address)) - f:close() - return ret, err -end - -function i2c_delete_device(bus, address) - local f, err = io.open(i2c_bus_path(bus) .. "/delete_device", "w") - if not f then return nil, err end - - ret, err = f:write(string.format("0x%02X", address)) - f:close() - return ret, err -end - -function i2c_get_mux_channels(parent, address) - local channels = {} - local channel_paths, glob_result = glob.glob(i2c_device_path(parent, address) .. "/channel-*", 0) - if not channel_paths then - if glob_result == glob.GLOB_NOMATCH then return channels end - if glob_result == glob.GLOB_ABORTED then return nil, "glob(): aborted" end - if glob_result == glob.GLOB_NOSPACE then return nil, "glob(): no space" end - return nil, "glob(): unknown error" - end - for _, channel_path in pairs(channel_paths) do - local channel = string.match(channel_path, '/channel%-(%d+)$') - if not channel then return nil, "unable to parse channel number from path: " .. channel_path end - - local bus_path, err = unistd.readlink(channel_path) - if not bus_path then return nil, err end - local bus = string.match(bus_path, '/i2c%-(%d+)$') - if not bus then return nil, "unable to parse bus number from path: " .. bus_path end - - channels[channel] = bus - end - return channels -end - --- ############# main ########### - --- assert(i2c_delete_device(0, 0x70)) --- time.nanosleep({tv_sec = 0, tv_nsec = 100000000}) -assert(i2c_add_device(0, "pca9548", 0x70)) -local mux_channels, err = i2c_get_mux_channels(0, 0x70) -if not mux_channels then error(err) end -for ch, bus in pairs(mux_channels) do - print(string.format("mux channel %d -> %s", ch, i2c_bus_path(bus))) -end - --- i2c_add_device(0, "ds2482", 0x18) --- i2c_add_device(0, "ads1115", 0x48) --- i2c_add_device(0, "bme280", 0x76) --- i2c_add_device(0, "bmp280", 0x77) --- i2c_add_device(0, "am2315", 0x5c) --- i2c_add_device(0, "mcp3221", 0x4d) +local num_sensors, err = sensors.setup(config) +if not num_sensors then error(err) end +print(string.format("successfully initialized %d sensor(s)", num_sensors)) diff --git a/files/common/openwrt/sensors.module_lua b/files/common/openwrt/sensors.module_lua new file mode 100644 index 00000000..f6c3e38c --- /dev/null +++ b/files/common/openwrt/sensors.module_lua @@ -0,0 +1,173 @@ +local base = _G +local io = require("io") +local string = require("string") +local cjson = require "cjson.safe" +local glob = require "posix.glob" +local time = require "posix.time" +local unistd = require "posix.unistd" + +local _M = {} +local _internal_ = {} +_internal_.setup = {} + +-- ############# i2c ########### + +function _internal_.write_to_file(path, data) + -- base.print(string.format("writing '%s' to '%s'", data, path)) + local f, err = io.open(path, "w") + if not f then return nil, err end + + ret, err = f:write(data) + f:close() + return ret, err +end + +function _internal_.read_from_file(path) + local f, err = io.open(path, "r") + if not f then return nil, err end + + data, err = f:read("*a") + f:close() + return data, err +end + +-- ############# i2c ########### + +function _M.i2c_bus_path(bus) + return string.format("/sys/bus/i2c/devices/i2c-%d", bus) +end + +function _M.i2c_device_name(bus, address) + return string.format("%d-%04X", bus, address) +end + +function _M.i2c_device_path(bus, address) + return string.format("/sys/bus/i2c/devices/" .. _M.i2c_device_name(bus, address)) +end + +function _M.i2c_add_device(bus, address, name) + return _internal_.write_to_file(_M.i2c_bus_path(bus) .. "/new_device", string.format("%s 0x%02X", name, address)) +end + +function _M.i2c_delete_device(bus, address) + return _internal_.write_to_file(_M.i2c_bus_path(bus) .. "/delete_device", string.format("0x%02X", address)) +end + +function _M.i2c_get_mux_channels(parent, address) + local channel_paths, glob_result = glob.glob(_M.i2c_device_path(parent, address) .. "/channel-*", 0) + if not channel_paths then + if glob_result == glob.GLOB_NOMATCH then return {} end + if glob_result == glob.GLOB_ABORTED then return nil, "glob(): aborted" end + if glob_result == glob.GLOB_NOSPACE then return nil, "glob(): no space" end + return nil, "glob(): unknown error" + end + + local channels = {} + for _, channel_path in base.pairs(channel_paths) do + local channel = string.match(channel_path, '/channel%-(%d+)$') + if not channel then return nil, "unable to parse channel number from path: " .. channel_path end + + local bus_path, err = unistd.readlink(channel_path) + if not bus_path then return nil, err end + local bus = string.match(bus_path, '/i2c%-(%d+)$') + if not bus then return nil, "unable to parse bus number from path: " .. bus_path end + + channels[tonumber(channel)] = tonumber(bus) + end + return channels +end + +function _M.i2c_add_devices_recursive(bus, devices) + local num_devices = 0 + local device + for _, device in base.ipairs(devices) do + -- base.print(string.format("i2c_add_device(%d, 0x%02X, %s)", bus, device.address, device.driver)) + _M.i2c_add_device(bus, device.address, device.driver) + num_devices = num_devices + 1 + + local setup_function = _internal_.setup[device.driver] + if setup_function ~= nil then + time.nanosleep({tv_sec = 0, tv_nsec = 100000000}) + setup_function(bus, device.address) + end + + if device.channels then + time.nanosleep({tv_sec = 0, tv_nsec = 100000000}) + local mux_channels, err = _M.i2c_get_mux_channels(bus, device.address) + if not mux_channels then return nil, error end + local channel + for _, channel in base.ipairs(device.channels) do + if not mux_channels[channel.number] then return nil, string.format("i2c-mux %s has no channel %d", _M.i2c_device_name(bus, device.address), channel.number) end + local tmp, err = _M.i2c_add_devices_recursive(mux_channels[channel.number], channel.devices) + if not tmp then return nil, err end + num_devices = num_devices + tmp + end + end + end + + return num_devices +end + + +-- ############# II0 ########### + +function _M.iio_device_path_from_i2c_device(bus, address) + local device_paths, glob_result = glob.glob(_M.i2c_device_path(bus, address) .. "/iio:device*", 0) + if not device_paths then + if glob_result == glob.GLOB_NOMATCH then return nil, "couldn't find IIO device handle for i2c device " .. _M.i2c_device_name(bus, address) end + if glob_result == glob.GLOB_ABORTED then return nil, "glob(): aborted" end + if glob_result == glob.GLOB_NOSPACE then return nil, "glob(): no space" end + return nil, "glob(): unknown error" + end + if #device_paths ~= 1 then return nil, "found more than one IIO device for i2c device " .. _M.i2c_device_name(bus, address) end + return device_paths[1] +end + +function _M.iio_setup_bmp280(bus, address) + local iio_device, err = _M.iio_device_path_from_i2c_device(bus, address) + if not iio_device then return nil, err end + + local ret, err = _internal_.write_to_file(iio_device .. '/in_pressure_oversampling_ratio', '1') + if not ret then return nil, err end + return _internal_.write_to_file(iio_device .. '/in_temp_oversampling_ratio', '1') +end +_internal_.setup['bmp280'] = _M.iio_setup_bmp280 + +function _M.iio_setup_bme280(bus, address) + local iio_device, err = _M.iio_device_path_from_i2c_device(bus, address) + if not iio_device then return nil, err end + + local ret, err = _internal_.write_to_file(iio_device .. '/in_humidityrelative_oversampling_ratio', '1') + if not ret then return nil, err end + local ret, err = _internal_.write_to_file(iio_device .. '/in_pressure_oversampling_ratio', '1') + if not ret then return nil, err end + return _internal_.write_to_file(iio_device .. '/in_temp_oversampling_ratio', '1') +end +_internal_.setup['bme280'] = _M.iio_setup_bme280 + + +-- ############# config ########### + +function _M.read_config(path) + sensors_json, err = _internal_.read_from_file(path) + if not sensors_json then return nil, err end + + return cjson.decode(sensors_json) +end + +function _M.setup(config) + local num_devices = 0 + if config.i2c then + local i2c_bus + for _, i2c_bus in ipairs(config.i2c) do + local tmp, err = _M.i2c_add_devices_recursive(i2c_bus.number, i2c_bus.devices) + if not tmp then return nil, err end + num_devices = num_devices + tmp + end + end +end + + +-- ################################ + +return _M diff --git a/inventory/group_vars/chaos-at-home-sensors/vars.yml b/inventory/group_vars/chaos-at-home-sensors/vars.yml index 2eea9b2c..7f4a93eb 100644 --- a/inventory/group_vars/chaos-at-home-sensors/vars.yml +++ b/inventory/group_vars/chaos-at-home-sensors/vars.yml @@ -1,5 +1,20 @@ --- sensornode_network_wired: no +sensornode_sensors: {} + +# TODO: add script to initialize i2c devices +## I2C Bus init examples: +## * add 8ch mux: echo "pca9548 0x70" > /sys/bus/i2c/devices/i2c-0/new_device +## * add DS2482: echo "ds2482 0x18" > /sys/bus/i2c/devices/i2c-0/new_device +## * add ADS1115: echo "ads1115 0x48" > /sys/bus/i2c/devices/i2c-0/new_device +## * add BME280: echo "bme280 0x76" > /sys/bus/i2c/devices/i2c-1/new_device +## * add BMP280: echo "bmp280 0x77" > /sys/bus/i2c/devices/i2c-1/new_device +## * add AM2315: echo "am2315 0x5c" > /sys/bus/i2c/devices/i2c-1/new_device +## * add MCP3221: echo "mcp3221 0x4d" > /sys/bus/i2c/devices/i2c-2/new_device + +# TODO: add collector for prometheus to export i2c-sensor data + + install_playbook: openwrt @@ -59,17 +74,15 @@ openwrt_mixin: /etc/htoprc: file: "{{ global_files_dir }}/common/htoprc" -# TODO: add script to initialize i2c devices -## I2C Bus init examples: -## * add 8ch mux: echo "pca9548 0x70" > /sys/bus/i2c/devices/i2c-0/new_device -## * add DS2482: echo "ds2482 0x18" > /sys/bus/i2c/devices/i2c-0/new_device -## * add ADS1115: echo "ads1115 0x48" > /sys/bus/i2c/devices/i2c-0/new_device -## * add BME280: echo "bme280 0x76" > /sys/bus/i2c/devices/i2c-1/new_device -## * add BMP280: echo "bmp280 0x77" > /sys/bus/i2c/devices/i2c-1/new_device -## * add AM2315: echo "am2315 0x5c" > /sys/bus/i2c/devices/i2c-1/new_device -## * add MCP3221: echo "mcp3221 0x4d" > /sys/bus/i2c/devices/i2c-2/new_device + /etc/sensors.json: + content: "{{ sensornode_sensors | to_nice_json(indent=2) }}\n" -# TODO: add collector for prometheus to export i2c-sensor data + /usr/lib/lua/sensors.lua: + file: "{{ global_files_dir }}/common/openwrt/sensors.module_lua" + + /usr/libexec/sensors-init.lua: + file: "{{ global_files_dir }}/common/openwrt/sensors-init.lua" + mode: "0755" openwrt_uci: diff --git a/inventory/host_vars/ch-sensors1.yml b/inventory/host_vars/ch-sensors1.yml index 52617de0..7efd03e4 100644 --- a/inventory/host_vars/ch-sensors1.yml +++ b/inventory/host_vars/ch-sensors1.yml @@ -1,25 +1,32 @@ --- #sensornode_network_wired: yes -senosrnode_sensors: +sensornode_sensors: i2c: - - bus: 0 + - number: 0 devices: - address: 0x70 driver: pca9548 channels: - - channel: 0 + - number: 0 devices: - name: foo address: 0x76 driver: bme280 - - channel: 1 + - number: 1 devices: - name: bar address: 0x77 driver: bmp280 - - channel: 2 + - number: 2 + devices: + - name: baz + address: 0x5c + driver: am2315 + - number: 7 devices: - address: 0x18 driver: ds2482 - 1wire: {} + 1wire: + - name: hugo + address: 28-012113511280 |