-
Notifications
You must be signed in to change notification settings - Fork 9
/
DL-CTD10.erl
110 lines (89 loc) · 3.06 KB
/
DL-CTD10.erl
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
% https://www.decentlab.com/products/pressure-/-liquid-level-temperature-and-electrical-conductivity-sensor-for-lorawan
-module(decentlab_decoder).
-define(PROTOCOL_VERSION, 2).
-export([decode/1, start/0]).
-define(SENSOR_DEFS,
[
#{
length => 4,
values => [
#{
name => <<"Water depth">>,
convert => fun(X) -> lists:nth(0 + 1, X) - 32768 end,
unit => <<"mm"/utf8>>
},
#{
name => <<"Temperature">>,
convert => fun(X) -> (lists:nth(1 + 1, X) - 32768) / 10 end,
unit => <<"°C"/utf8>>
},
#{
name => <<"Electrical conductivity">>,
convert => fun(X) -> lists:nth(2 + 1, X) end,
unit => <<"µS⋅cm⁻¹"/utf8>>
},
#{
name => <<"Freezing flag">>,
convert => fun(X) -> lists:nth(3 + 1, X) end
}
]
},
#{
length => 1,
values => [
#{
name => <<"Battery voltage">>,
convert => fun(X) -> lists:nth(0 + 1, X) / 1000 end,
unit => <<"V"/utf8>>
}
]
}
]
).
decode(<<?PROTOCOL_VERSION, DeviceId:16,
Flags:16/bitstring, Bytes/binary>> = Binary) when is_binary(Binary) ->
Words = bytes_to_words(Bytes),
maps:merge(#{<<"Protocol version">> => ?PROTOCOL_VERSION,
<<"Device ID">> => DeviceId},
sensor(Words, Flags, ?SENSOR_DEFS));
decode(HexStr) ->
Binary = hex2bin(HexStr),
decode(Binary).
start() ->
io:format("~p~n", [decode("0207d9000390888081006400000c60")]),
io:format("~p~n", [decode("0207d900020c60")]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% PRIVATE FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
sensor(_Words, _Flags, []) -> #{};
sensor(Words, <<Flags:15, 0:1>>, [_Cur | Rest]) ->
sensor(Words, <<0:1, Flags:15>>, Rest);
sensor(Words, <<Flags:15, 1:1>>,
[#{length := Len, values := ValueDefs} | RestDefs]) ->
{X, RestWords} = lists:split(Len, Words),
Values = value(ValueDefs, X),
RestSensors = sensor(RestWords, <<0:1, Flags:15>>, RestDefs),
maps:merge(Values, RestSensors).
value([], _X) -> #{};
value([#{convert := Convert,
name := Name} = ValueDef | RestDefs], X) ->
Values = value(RestDefs, X),
Value = #{<<"value">> => Convert(X)},
Value2 = add_unit(Value, ValueDef),
maps:put(Name, Value2, Values);
value([_NoConvert | RestDefs], X) -> value(RestDefs, X).
add_unit(Value, #{unit := Unit}) ->
maps:put(<<"unit">>, Unit, Value);
add_unit(Value, _NoUnit) ->
Value.
hex2bin(HexStr) when is_binary(HexStr) -> hex2bin(binary_to_list(HexStr));
hex2bin(HexStr) -> hex2bin(HexStr, []).
hex2bin("", Bins) -> list_to_binary(lists:reverse(Bins));
hex2bin(HexStr, Bins) ->
Bytes = string:slice(HexStr, 0, 2),
Word = list_to_integer(Bytes, 16),
hex2bin(string:slice(HexStr, 2), [Word | Bins]).
bytes_to_words(Bytes) -> bytes_to_words(Bytes, []).
bytes_to_words(<<>>, Words) -> lists:reverse(Words);
bytes_to_words(<<Word:16, Rest/binary>>, Words) ->
bytes_to_words(Rest, [Word | Words]).
where(true, IfTrue, _IfFalse) -> IfTrue;
where(false, _IfTrue, IfFalse) -> IfFalse.