summaryrefslogtreecommitdiff
path: root/sen5x.lua
blob: 13bd972f1e799ce7cf0a37a455246ab6b419c139 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
local sen5x = {}
local device_address = 0x69

sen5x.bus_id = 0

function sen5x.start()
	i2c.start(sen5x.bus_id)
	if not i2c.address(sen5x.bus_id, device_address, i2c.TRANSMITTER) then
		return false
	end
	i2c.write(sen5x.bus_id, {0x00, 0x21})
	i2c.stop(sen5x.bus_id)
	return true
end

function sen5x.stop()
	i2c.start(sen5x.bus_id)
	if not i2c.address(sen5x.bus_id, device_address, i2c.TRANSMITTER) then
		return false
	end
	i2c.write(sen5x.bus_id, {0x01, 0x04})
	i2c.stop(sen5x.bus_id)
	return true
end

function sen5x.read_value(data, index)
	local val = string.byte(data, index) * 256 + string.byte(data, index+1)
	if val == 0xffff or val == 0x7fff then
		val = nil
	end
	return val
end

function sen5x.prepare_read()
	i2c.start(sen5x.bus_id)
	if not i2c.address(sen5x.bus_id, device_address, i2c.TRANSMITTER) then
		return false
	end
	i2c.write(sen5x.bus_id, {0x03, 0xc4})
	i2c.stop(sen5x.bus_id)
	return true
end

function sen5x.read()
	i2c.start(sen5x.bus_id)
	if not i2c.address(sen5x.bus_id, device_address, i2c.RECEIVER) then
		return false
	end
	local data = i2c.read(sen5x.bus_id, 24)
	i2c.stop(sen5x.bus_id)
	if not sen5x.crc_valid(data, 24) then
		return false
	end
	sen5x.pm1 = sen5x.read_value(data, 1)
	sen5x.pm2_5 = sen5x.read_value(data, 4)
	sen5x.pm4 = sen5x.read_value(data, 7)
	sen5x.pm10 = sen5x.read_value(data, 10)
	sen5x.humidity = sen5x.read_value(data, 13)
	sen5x.temperature = sen5x.read_value(data, 16)
	sen5x.voc = sen5x.read_value(data, 19)
	sen5x.nox = sen5x.read_value(data, 22)
	return true
end

function sen5x.prepare_get_product()
	i2c.start(sen5x.bus_id)
	if not i2c.address(sen5x.bus_id, device_address, i2c.TRANSMITTER) then
		return false
	end
	i2c.write(sen5x.bus_id, {0xd0, 0x14})
	i2c.stop(sen5x.bus_id)
	return true
end

function sen5x.get_product()
	i2c.start(sen5x.bus_id)
	if not i2c.address(sen5x.bus_id, device_address, i2c.RECEIVER) then
		return nil
	end
	local data = i2c.read(sen5x.bus_id, 48)
	i2c.stop(sen5x.bus_id)
	if not sen5x.crc_valid(data, 48) then
		return false
	end
	local ret = ""
	ret = ret .. string.sub(data, 1, 2)
	ret = ret .. string.sub(data, 4, 5)
	ret = ret .. string.sub(data, 7, 7)
	return ret
end

function sen5x.crc_word(data, index)
	local crc = 0xff
	for i = index, index+1 do
		crc = bit.bxor(crc, string.byte(data, i))
		for j = 8, 1, -1 do
			if bit.isset(crc, 7) then
				crc = bit.bxor(bit.lshift(crc, 1), 0x31)
			else
				crc = bit.lshift(crc, 1)
			end
			crc = bit.band(crc, 0xff)
		end
	end
	return bit.band(crc, 0xff)
end

function sen5x.crc_valid(data, length)
	for i = 1, length, 3 do
		if sen5x.crc_word(data, i) ~= string.byte(data, i+2) then
			return false
		end
	end
	return true
end

return sen5x