/* https://www.decentlab.com/support */ using System; using System.IO; using System.Collections.Generic; public class DecentlabDecoder { private delegate double conversion(double[] x); public const int PROTOCOL_VERSION = 2; private class Sensor { internal int length { get; set; } internal List values { get; set; } internal Sensor(int length, List values) { this.length = length; this.values = values; } } private class SensorValue { internal string name { get; set; } internal string unit { get; set; } internal conversion convert; internal SensorValue(string name, string unit, conversion convert) { this.name = name; this.unit = unit; this.convert = convert; } } private static readonly List SENSORS = new List() { new Sensor(2, new List() { new SensorValue("Air temperature", "°C", x => 175 * x[0] / 65535 - 45), new SensorValue("Air humidity", "%", x => 100 * x[1] / 65535) }), new Sensor(2, new List() { new SensorValue("Surface temperature", "°C", x => (x[0] - 1000) / 10), new SensorValue("Head temperature", "°C", x => (x[1] - 1000) / 10) }), new Sensor(1, new List() { new SensorValue("Battery voltage", "V", x => x[0] / 1000) }) }; private static int ReadInt(Stream stream) { return (stream.ReadByte() << 8) + stream.ReadByte(); } public static Dictionary> Decode(byte[] msg) { return Decode(new MemoryStream(msg)); } public static Dictionary> Decode(String msg) { byte[] output = new byte[msg.Length / 2]; for (int i = 0, j = 0; i < msg.Length; i += 2, j++) { output[j] = (byte)int.Parse(msg.Substring(i, 2), System.Globalization.NumberStyles.HexNumber); } return Decode(output); } public static Dictionary> Decode(Stream msg) { var version = msg.ReadByte(); if (version != PROTOCOL_VERSION) { throw new InvalidDataException("protocol version " + version + " doesn't match v2"); } var result = new Dictionary>(); result["Protocol version"] = new Tuple(version, null); var deviceId = ReadInt(msg); result["Device ID"] = new Tuple(deviceId, null); var flags = ReadInt(msg); foreach (var sensor in SENSORS) { if ((flags & 1) == 1) { double[] x = new double[sensor.length]; for (int i = 0; i < sensor.length; i++) { x[i] = ReadInt(msg); } foreach (var val in sensor.values) { if (val.convert != null) { result[val.name] = new Tuple(val.convert(x), val.unit); } } } flags >>= 1; } return result; } } public class Program { public static void Main() { var payloads = new string[] { "021a10000764a079b104f904c40c60", "021a1000040c60" }; foreach (var pl in payloads) { var decoded = DecentlabDecoder.Decode(pl); foreach (var k in decoded.Keys) { Console.WriteLine(k + ": " + decoded[k]); } Console.WriteLine(); } } }