1use core::{fmt::Write, str::FromStr};
6
7use heapless::String;
8use fuga_json_seq_parser::{JsonScalarValue, ParserCallbackAction, JsonNode};
9use fuga_json_seq_parser::Parser as JsonParser;
10use fuga_json_seq_parser::ParserError as JsonParserError;
11
12use nom::{
13 character::complete::one_of,
14 combinator::{map, recognize},
15 error::{ContextError, ParseError},
16 sequence::{pair, separated_pair},
17 IResult,
18};
19use uuid::Uuid;
20use crate::config::*;
21use crate::common_types::*;
22use crate::node_key::*;
23use crate::parser_options::{ParserOptions, copy_string_option};
24
25#[derive(Clone, Debug, Default)]
26pub struct SensorValue {
27 pub val: f32,
28 pub created_at: Timestamp,
29}
30#[derive(Debug, Default)]
31pub struct User {
32 pub id: Uuid,
33 pub nickname: String<MAX_NICKNAME_LEN>,
34 pub superuser: bool,
35}
36
37#[derive(Clone, Debug, Default)]
38pub struct NewestEvents {
39 pub temperature: Option<SensorValue>,
40 pub humidity: Option<SensorValue>,
41 pub illumination: Option<SensorValue>,
42 pub motion: Option<SensorValue>,
43}
44
45#[derive(Clone, Debug, Default, PartialEq)]
46pub struct Device {
47 pub id: Uuid,
48 pub name: String<MAX_DEVICE_NAME_LEN>,
49 pub temperature_offset: f32,
50 pub humidity_offset: f32,
51 pub created_at: Timestamp,
52 pub updated_at: Timestamp,
53 pub firmware_version: String<MAX_FIRMWARE_VERSION_LEN>,
54 pub mac_address: MacAddress,
55 pub bt_mac_address: MacAddress,
56 pub serial_number: SerialNumber,
57}
58
59#[derive(Debug, Default)]
60pub struct Model {
61 pub id: Uuid,
62 pub country: String<MAX_COUNTRY_LEN>,
63 pub manifacturer: String<MAX_MANUFACTURER_LEN>,
64 pub remote_name: String<MAX_REMOTE_NAME_LEN>,
65 pub series: String<MAX_SERIES_LEN>,
66 pub name: String<MAX_MODEL_NAME_LEN>,
67 pub image: String<MAX_IMAGE_LEN>,
68}
69
70#[derive(Debug)]
71pub enum DeviceSubNode {
72 User(User),
73 NewestEvents(NewestEvents),
74}
75
76type DevicesParser = JsonParser<REQUIRED_DEVICES_PARSER_BUFFER_LEN, 5>;
77
78#[derive(Clone, Copy, Debug)]
79enum DevicesParserState {
80 Start,
81 DevicesArray,
82 DeviceMap,
83 UsersArray,
84 UserMap,
85 NewestEventsMap,
86 NewestEventMap(NewestEventType),
87 UnknownMapArray,
88}
89
90#[derive(Clone, Copy, Debug)]
91enum NewestEventType {
92 Temperature,
93 Humidity,
94 Illumination,
95 Motion,
96}
97
98#[derive(Clone, Copy, Debug, PartialEq, Eq)]
99pub struct MacAddress(pub [u8; 6]);
100
101impl Default for MacAddress {
102 fn default() -> Self {
103 Self([0u8; 6])
104 }
105}
106
107fn parse_byte_string<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
108 i: &'a str,
109) -> IResult<&'a str, u8, E> {
110 let hex_char_list = "0123456789ABCDEFabcdef";
111 map(
112 recognize(pair(one_of(hex_char_list), one_of(hex_char_list))),
113 |byte_str| u8::from_str_radix(byte_str, 16).unwrap(),
114 )(i)
115}
116
117fn parse_mac_address<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
118 i: &'a str,
119) -> IResult<&'a str, [u8; 6], E> {
120 let delimiter_list = ":-";
121
122 map(
123 separated_pair(
124 parse_byte_string,
125 one_of(delimiter_list),
126 separated_pair(
127 parse_byte_string,
128 one_of(delimiter_list),
129 separated_pair(
130 parse_byte_string,
131 one_of(delimiter_list),
132 separated_pair(
133 parse_byte_string,
134 one_of(delimiter_list),
135 separated_pair(
136 parse_byte_string,
137 one_of(delimiter_list),
138 parse_byte_string,
139 ),
140 ),
141 ),
142 ),
143 ),
144 |(l, r)| [l, r.0, r.1 .0, r.1 .1 .0, r.1 .1 .1 .0, r.1 .1 .1 .1],
145 )(i)
146}
147
148impl FromStr for MacAddress {
149 type Err = ModelNodeParseError;
150 fn from_str(s: &str) -> Result<Self, Self::Err> {
151 let (_, mac_address) = parse_mac_address(s)
152 .map_err(|_: nom::Err<()>| ModelNodeParseError::MacAddressParseError)?;
153 Ok(Self(mac_address))
154 }
155}
156
157pub fn read_devices<R: embedded_io::blocking::Read, F>(
158 reader: &mut R,
159 total_length: Option<usize>,
160 options: &ParserOptions,
161 mut callback: F,
162) -> Result<(), JsonParserError<R::Error, ModelNodeParseError>>
163where
164 F: for<'a> FnMut(&'a Device, Option<&'a DeviceSubNode>),
165{
166 let mut parser = DevicesParser::new();
167 parser.set_bytes_remaining(total_length);
168 let mut device = Device::default();
169 let mut subnode = DeviceSubNode::User(User::default());
170 let mut state = DevicesParserState::Start;
171 let mut node_key = None;
172 let mut unknown_map_depth = 0;
173 let mut unknown_array_depth = 0;
174
175 while !parser.parse(reader, |node| {
176 let new_state = match (state, node) {
177 (DevicesParserState::Start, JsonNode::StartArray) => {
178 DevicesParserState::DevicesArray
179 }
180 (DevicesParserState::DevicesArray, JsonNode::EndArray) => {
181 DevicesParserState::Start
182 }
183 (DevicesParserState::DevicesArray, JsonNode::StartMap) => {
184 DevicesParserState::DeviceMap
185 }
186 (DevicesParserState::DeviceMap, JsonNode::EndMap) => {
187 DevicesParserState::DevicesArray
188 }
189 (map_state, JsonNode::Key(key)) => {
190 match key {
191 JsonScalarValue::String(key) => {
192 node_key = ModelNodeKey::try_from(key).ok(); }
194 _ => {}
195 }
196 map_state
197 }
198 (DevicesParserState::DeviceMap, JsonNode::Value(value)) => {
200 if let Some(node_key) = node_key.take() {
201 match (node_key, value) {
202 (ModelNodeKey::Name, JsonScalarValue::String(s)) => {
203 device.name = copy_string_option(s, options)?;
204 }
205 (ModelNodeKey::Id, JsonScalarValue::String(s)) => {
206 device.id = Uuid::from_str(s)?
207 }
208 (ModelNodeKey::CreatedAt, JsonScalarValue::String(s)) => {
209 device.created_at = Timestamp::from_str(s)?
210 }
211 (ModelNodeKey::UpdatedAt, JsonScalarValue::String(s)) => {
212 device.updated_at = Timestamp::from_str(s)?
213 }
214 (ModelNodeKey::MacAddress, JsonScalarValue::String(s)) => {
215 device.mac_address = MacAddress::from_str(s)?
216 }
217 (ModelNodeKey::BtMacAddress, JsonScalarValue::String(s)) => {
218 device.bt_mac_address = MacAddress::from_str(s)?
219 }
220 (ModelNodeKey::SerialNumber, JsonScalarValue::String(s)) => {
221 device.serial_number = copy_string_option(s, options)?;
222 }
223 (ModelNodeKey::FirmwareVersion, JsonScalarValue::String(s)) => {
224 device.firmware_version = copy_string_option(s, options)?;
225 }
226 (ModelNodeKey::TemperatureOffset, JsonScalarValue::Number(n)) => {
227 device.temperature_offset = n.into()
228 }
229 (ModelNodeKey::HumidityOffset, JsonScalarValue::Number(n)) => {
230 device.humidity_offset = n.into()
231 }
232 _ => {} }
234 }
235 DevicesParserState::DeviceMap
236 }
237 (DevicesParserState::DeviceMap, JsonNode::StartArray) => {
238 match node_key.take() {
239 Some(ModelNodeKey::Users) => {
240 callback(&device, None);
242 DevicesParserState::UsersArray
243 }
244 _ => {
245 unknown_array_depth += 1;
246 DevicesParserState::UnknownMapArray
247 }
248 }
249 }
250 (DevicesParserState::DeviceMap, JsonNode::StartMap) => match node_key.take() {
251 Some(ModelNodeKey::NewestEvents) => {
252 subnode = DeviceSubNode::NewestEvents(NewestEvents::default());
253 DevicesParserState::NewestEventsMap
254 }
255 _ => {
256 unknown_map_depth += 1;
257 DevicesParserState::UnknownMapArray
258 }
259 },
260
261 (DevicesParserState::UsersArray, JsonNode::EndArray) => {
263 DevicesParserState::DeviceMap
264 } (DevicesParserState::UsersArray, JsonNode::StartMap) => {
266 subnode = DeviceSubNode::User(User::default());
267 DevicesParserState::UserMap
268 }
269 (DevicesParserState::UserMap, JsonNode::Value(value)) => {
271 if let DeviceSubNode::User(ref mut user) = &mut subnode {
272 if let Some(node_key) = node_key.take() {
273 match (node_key, value) {
274 (ModelNodeKey::Id, JsonScalarValue::String(s)) => {
275 user.id = Uuid::from_str(s)?
276 }
277 (ModelNodeKey::NickName, JsonScalarValue::String(s)) => {
278 user.nickname = copy_string_option(s, options)?;
279 }
280 (ModelNodeKey::SuperUser, JsonScalarValue::Boolean(v)) => {
281 user.superuser = v
282 }
283 _ => {} }
285 }
286 }
287 DevicesParserState::UserMap
288 }
289 (DevicesParserState::UserMap, JsonNode::EndMap) => {
290 callback(&device, Some(&subnode));
291 DevicesParserState::UsersArray }
293 (DevicesParserState::NewestEventsMap, JsonNode::EndMap) => {
295 callback(&device, Some(&subnode));
296 DevicesParserState::DeviceMap }
298 (DevicesParserState::NewestEventsMap, JsonNode::StartMap) => {
299 let newest_events = if let DeviceSubNode::NewestEvents(ref mut newest_events) =
300 &mut subnode
301 {
302 newest_events
303 } else {
304 panic!(
305 "sub_node must contains newest_events at (NewestEventsMap, StartMap) state"
306 );
307 };
308
309 match node_key.take() {
310 Some(ModelNodeKey::Te) => {
311 newest_events.temperature = Some(SensorValue::default());
312 DevicesParserState::NewestEventMap(NewestEventType::Temperature)
313 }
314 Some(ModelNodeKey::Hu) => {
315 newest_events.humidity = Some(SensorValue::default());
316 DevicesParserState::NewestEventMap(NewestEventType::Humidity)
317 }
318 Some(ModelNodeKey::Il) => {
319 newest_events.illumination = Some(SensorValue::default());
320 DevicesParserState::NewestEventMap(NewestEventType::Illumination)
321 }
322 Some(ModelNodeKey::Mo) => {
323 newest_events.motion = Some(SensorValue::default());
324 DevicesParserState::NewestEventMap(NewestEventType::Motion)
325 }
326 _ => return Err(ModelNodeParseError::UnknownNewestEventsType),
327 }
328 }
329 (
331 DevicesParserState::NewestEventMap(newest_event_type),
332 JsonNode::Value(value),
333 ) => {
334 if let DeviceSubNode::NewestEvents(ref mut newest_events) = &mut subnode {
335 let sensor_value = match newest_event_type {
336 NewestEventType::Temperature => newest_events.temperature.as_mut().unwrap(),
337 NewestEventType::Humidity => newest_events.humidity.as_mut().unwrap(),
338 NewestEventType::Illumination => {
339 newest_events.illumination.as_mut().unwrap()
340 }
341 NewestEventType::Motion => newest_events.motion.as_mut().unwrap(),
342 };
343 match (node_key.take(), value) {
344 (Some(ModelNodeKey::Val), JsonScalarValue::Number(n)) => {
345 sensor_value.val = n.into()
346 }
347 (Some(ModelNodeKey::CreatedAt), JsonScalarValue::String(s)) => {
348 sensor_value.created_at = Timestamp::from_str(s)?
349 }
350 _ => {}
351 }
352 }
353 DevicesParserState::NewestEventMap(newest_event_type)
354 }
355 (DevicesParserState::NewestEventMap(_), JsonNode::EndMap) => {
356 DevicesParserState::NewestEventsMap
357 }
358
359 (DevicesParserState::UnknownMapArray, JsonNode::StartArray) => {
361 unknown_array_depth += 1;
362 DevicesParserState::UnknownMapArray
363 }
364 (DevicesParserState::UnknownMapArray, JsonNode::StartMap) => {
365 unknown_map_depth += 1;
366 DevicesParserState::UnknownMapArray
367 }
368 (DevicesParserState::UnknownMapArray, JsonNode::EndArray) => {
369 unknown_array_depth -= 1;
370 if unknown_array_depth == 0 && unknown_map_depth == 0 {
371 DevicesParserState::DeviceMap
372 } else {
373 DevicesParserState::UnknownMapArray
374 }
375 }
376 (DevicesParserState::UnknownMapArray, JsonNode::EndMap) => {
377 unknown_map_depth -= 1;
378 if unknown_array_depth == 0 && unknown_map_depth == 0 {
379 DevicesParserState::DeviceMap
380 } else {
381 DevicesParserState::UnknownMapArray
382 }
383 }
384 (DevicesParserState::UnknownMapArray, _) => DevicesParserState::UnknownMapArray, (state, json_node) => {
386 let mut error = UnexpectedNodeError::new();
387 write!(&mut error, "{:?}", (state, json_node)).ok();
388 return Err(ModelNodeParseError::UnexpectedNode(error));
389 }
390 };
391 state = new_state;
392 Ok(ParserCallbackAction::Nothing)
393 })? {}
394 Ok(())
395}
396
397#[cfg(test)]
398mod test {
399 use fuga_json_seq_parser::BufferReader;
400 use uuid::uuid;
401
402 use super::*;
403
404 fn create_reader<'a>(input: &'a str) -> (usize, BufferReader<'a>) {
405 let total_length = input.as_bytes().len();
406 (total_length, BufferReader::new(input.as_bytes()))
407 }
408
409 #[test]
410 fn test_parse_mac_address_colon() {
411 let parsed = MacAddress::from_str("f0:08:d1:00:11:22").unwrap();
412 assert_eq!(parsed, MacAddress([0xf0, 0x08, 0xd1, 0x00, 0x11, 0x22]));
413 }
414 #[test]
415 fn test_parse_mac_address_hyphen() {
416 let parsed = MacAddress::from_str("f0-08-d1-00-11-22").unwrap();
417 assert_eq!(parsed, MacAddress([0xf0, 0x08, 0xd1, 0x00, 0x11, 0x22]));
418 }
419
420 #[test]
421 fn test_parse_empty_devices() {
422 let (length, mut reader) = create_reader(
423 "
424 [
425 ]
426 ",
427 );
428 read_devices(&mut reader, Some(length), &ParserOptions::default(), |_device, _sub_node| {
429 panic!("callback must not be called for empty devices.");
430 })
431 .unwrap();
432 }
433 #[test]
434 fn test_parse_devices() {
435 let (length, mut reader) = create_reader(include_str!("../data/devices.json"));
436 let expected_devices = [
437 Device {
438 name: String::from("test remo device hoge"),
439 id: uuid!("f262cb0c-a853-47bb-9559-44d0f2c4d6e2"),
440 created_at: Timestamp::from_str("2022-10-18T06:42:59Z").unwrap(),
441 updated_at: Timestamp::from_str("2022-10-19T05:22:28Z").unwrap(),
442 mac_address: MacAddress::from_str("e8:db:84:00:11:22").unwrap(),
443 bt_mac_address: MacAddress::from_str("e8:db:84:22:33:44").unwrap(),
444 serial_number: String::from("2B012345678901"),
445 firmware_version: String::from("Remo-mini/1.10.0"),
446 temperature_offset: -0.5,
447 humidity_offset: 1.5,
448 },
449 Device {
450 name: String::from("Remo"),
451 id: uuid!("12948215-568a-49ca-be45-c556e8140c56"),
452 created_at: Timestamp::from_str("2022-10-07T05:57:52Z").unwrap(),
453 updated_at: Timestamp::from_str("2022-10-07T05:57:52Z").unwrap(),
454 mac_address: MacAddress::from_str("24:6f:28:00:11:22").unwrap(),
455 bt_mac_address: MacAddress::from_str("24:6f:28:22:33:44").unwrap(),
456 serial_number: String::from("1W012345678901"),
457 firmware_version: String::from("Remo/1.10.0"),
458 temperature_offset: 1.0,
459 humidity_offset: 0.0,
460 },
461 Device {
462 name: String::from("Remo E lite"),
463 id: uuid!("b08bdb7b-a2ad-4c3c-88f6-68645ae98077"),
464 created_at: Timestamp::from_str("2022-08-22T05:51:50Z").unwrap(),
465 updated_at: Timestamp::from_str("2022-10-03T04:16:16Z").unwrap(),
466 mac_address: MacAddress::from_str("f0:08:d1:00:11:22").unwrap(),
467 bt_mac_address: MacAddress::from_str("f0:08:d1:22:33:44").unwrap(),
468 serial_number: String::from("4W012345678901"),
469 firmware_version: String::from("Remo-E-lite/1.7.4"),
470 temperature_offset: 0.0,
471 humidity_offset: 0.0,
472 },
473 ];
474 let mut expected_devices_iter = expected_devices.iter();
475 read_devices(
476 &mut reader,
477 Some(length),
478 &ParserOptions::default(),
479 |device, sub_node| match sub_node {
480 None => {
481 let expected_device = expected_devices_iter.next();
482 assert!(
483 expected_device.is_some(),
484 "Extra device returned from parser - {:?}",
485 device
486 );
487 let expected_device = expected_device.unwrap();
488 assert_eq!(device, expected_device, "Device mismatch.");
489 }
490 _ => {}
491 },
492 )
493 .unwrap();
494 }
495}