-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
honeywell.c
150 lines (124 loc) · 4.46 KB
/
honeywell.c
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/** @file
Honeywell (Ademco) Door/Window Sensors (345Mhz).
Copyright (C) 2016 adam1010
Copyright (C) 2019 Christian W. Zuckschwerdt <zany@triq.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
/**
Honeywell (Ademco) Door/Window Sensors (345.0Mhz).
Tested with the Honeywell 5811 Wireless Door/Window transmitters.
Also: 2Gig DW10 door sensors,
and Resolution Products RE208 (wire to air repeater).
And DW11 with 96 bit packets.
Maybe: 5890PI?
64 bit packets, repeated multiple times per open/close event.
Protocol whitepaper: "DEFCON 22: Home Insecurity" by Logan Lamb.
Data layout:
PP PP C IIIII EE SS SS
- P: 16bit Preamble and sync bit (always ff fe)
- C: 4bit Channel
- I: 20bit Device serial number / or counter value
- E: 8bit Event, where 0x80 = Open/Close, 0x04 = Heartbeat / or id
- S: 16bit CRC
*/
#include "decoder.h"
static int honeywell_decode(r_device *decoder, bitbuffer_t *bitbuffer)
{
// full preamble is 0xFFFE
uint8_t const preamble_pattern[2] = {0xff, 0xe0}; // 12 bits
data_t *data;
int row;
int pos;
int len;
uint8_t b[10] = {0};
int channel;
int device_id;
int event;
uint16_t crc_calculated;
uint16_t crc;
int reed;
int contact;
int heartbeat;
int alarm;
int tamper;
int battery_low;
row = 0; // we expect a single row only. reduce collisions
if (bitbuffer->num_rows != 1 || bitbuffer->bits_per_row[row] < 60)
return DECODE_ABORT_LENGTH;
bitbuffer_invert(bitbuffer);
pos = bitbuffer_search(bitbuffer, row, 0, preamble_pattern, 12) + 12;
len = bitbuffer->bits_per_row[row] - pos;
if (len < 48)
return DECODE_ABORT_LENGTH;
bitbuffer_extract_bytes(bitbuffer, row, pos, b, 80);
channel = b[0] >> 4;
device_id = ((b[0] & 0xf) << 16) | (b[1] << 8) | b[2];
crc = (b[4] << 8) | b[5];
if (device_id == 0 && crc == 0)
return DECODE_ABORT_EARLY; // Reduce collisions
if (len > 50) { // DW11
decoder_log_bitrow(decoder, 1, __func__, b, (len > 80 ? 80 : len), "");
}
if (channel == 0x2 || channel == 0x4 || channel == 0xA) {
// 2GIG brand
crc_calculated = crc16(b, 4, 0x8050, 0);
} else { // channel == 0x8
crc_calculated = crc16(b, 4, 0x8005, 0);
}
if (crc != crc_calculated)
return DECODE_FAIL_MIC; // Not a valid packet
event = b[3];
// decoded event bits: CTRABHUU
// NOTE: not sure if these apply to all device types
contact = (event & 0x80) >> 7;
tamper = (event & 0x40) >> 6;
reed = (event & 0x20) >> 5;
alarm = (event & 0x10) >> 4;
battery_low = (event & 0x08) >> 3;
heartbeat = (event & 0x04) >> 2;
/* clang-format off */
data = data_make(
"model", "", DATA_STRING, "Honeywell-Security",
"id", "", DATA_FORMAT, "%05x", DATA_INT, device_id,
"channel", "", DATA_INT, channel,
"event", "", DATA_FORMAT, "%02x", DATA_INT, event,
"state", "", DATA_STRING, contact ? "open" : "closed", // Ignore the reed switch legacy.
"contact_open", "", DATA_INT, contact,
"reed_open", "", DATA_INT, reed,
"alarm", "", DATA_INT, alarm,
"tamper", "", DATA_INT, tamper,
"battery_ok", "Battery", DATA_INT, !battery_low,
"heartbeat", "", DATA_INT, heartbeat,
"mic", "Integrity", DATA_STRING, "CRC",
NULL);
/* clang-format on */
decoder_output_data(decoder, data);
return 1;
}
static char const *const output_fields[] = {
"model",
"id",
"channel",
"event",
"state",
"contact_open",
"reed_open",
"alarm",
"tamper",
"battery_ok",
"heartbeat",
"mic",
NULL,
};
r_device const honeywell = {
.name = "Honeywell Door/Window Sensor, 2Gig DW10/DW11, RE208 repeater",
.modulation = OOK_PULSE_MANCHESTER_ZEROBIT,
.short_width = 156,
.long_width = 0,
.reset_limit = 292,
.decode_fn = &honeywell_decode,
.fields = output_fields,
};