diff --git a/sites/en/static/js/language-switcher.js b/sites/en/static/js/language-switcher.js index 050a1e1f64544..9c8bd3c479a06 100644 --- a/sites/en/static/js/language-switcher.js +++ b/sites/en/static/js/language-switcher.js @@ -1,6 +1,6 @@ // 语言切换器 - 生产环境优化版本 -// 生成时间: 2026-03-11 13:45:57 (北京时间) -// 多语言页面: 2207 个 +// 生成时间: 2026-03-12 17:40:12 (北京时间) +// 多语言页面: 2209 个 (function() { 'use strict'; @@ -13186,6 +13186,16 @@ "es", "ja" ], + "/t2000_faq": [ + "cn", + "es", + "ja" + ], + "/t2000_payload_format": [ + "cn", + "es", + "ja" + ], "/": [ "en", "cn", diff --git a/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/es_FAQ.md b/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/es_FAQ.md new file mode 100644 index 0000000000000..0c2f60cbd3e1e --- /dev/null +++ b/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/es_FAQ.md @@ -0,0 +1,136 @@ +--- +description: Preguntas frecuentes sobre el rastreador SenseCAP T2000 +title: Preguntas frecuentes +keywords: + - Tracker + - SenseCAP +image: https://files.seeedstudio.com/wiki/SenseCAP/SenseCAP_T2000_Tracker/SenseCAP_T2000_Tracker_QuickStart.webp +slug: /t2000_faq +last_update: + date: 3/12/2026 + author: Janet +createdAt: '2026-03-12' +updatedAt: '2026-03-12' +url: https://wiki.seeedstudio.com/es/t2000_faq/ +--- + +# Preguntas frecuentes + +### Relacionado con la localización + +
+¿Cuál es la precisión típica de posicionamiento GNSS del T2000? + +- En condiciones de cielo abierto, la precisión de posicionamiento GNSS del T2000 suele alcanzar un nivel de precisión de metros. +- Los resultados de las pruebas muestran un CEP50 (Error Circular Probable al 50%) de aproximadamente **5–7 metros**, lo que significa que más de la mitad de los puntos de localización caen dentro de este rango respecto a la posición real. +- La precisión de posicionamiento real puede variar según el entorno, la visibilidad de los satélites, las condiciones de instalación, etc. + + +
+ + +
+¿Por qué a veces el posicionamiento GNSS muestra deriva o no hay datos de latitud y longitud GNSS? + +- La precisión del GNSS puede verse afectada por varios factores ambientales: + - Edificios, árboles u otros obstáculos que bloquean las señales de los satélites. + - Efectos multitrayectoria causados por reflexiones de señales en paredes o superficies metálicas. + - Interferencias electromagnéticas de equipos electrónicos cercanos. + - Mala orientación de la antena o lugar de instalación inadecuado. + +- En algunos casos, el dispositivo puede no informar datos de latitud y longitud GNSS porque el escaneo GNSS ha excedido el tiempo de espera. Este estado puede verse en la carga útil de subida, donde el campo de **estado de posicionamiento** mostrará **"GNSS scan timeout"** debido a las mismas condiciones ambientales mencionadas anteriormente. + +- Para obtener los mejores resultados, instala el dispositivo en un área exterior abierta con una vista despejada del cielo. + +
+ + +
+¿Cómo se debe instalar el T2000 para lograr el mejor rendimiento GNSS? + +- Coloca el dispositivo en un entorno abierto con obstrucción mínima a las señales de los satélites. +- Asegúrate de que el área de la antena GNSS esté orientada hacia arriba, hacia el cielo. +- Evita instalar el dispositivo cerca de objetos metálicos grandes o estructuras densas. +- Evita cubrir el dispositivo o colocarlo dentro de recintos metálicos sellados. +![Antenna](https://files.seeedstudio.com/wiki/SenseCAP/SenseCAP_T2000_Tracker/T2000-antenna.png) + +
+ +
+¿Por qué la localización por Wi‑Fi o Bluetooth no se muestra en el mapa de la app SenseCraft? + +- La localización por Wi‑Fi y Bluetooth requiere un servicio de análisis de mapas de terceros, que debe ser invocado por los usuarios para el análisis. Actualmente, la app SenseCraft solo admite la visualización de posicionamiento GNSS. + +
+ +
+ +Para más detalles sobre el posicionamiento GNSS, consulta el blog: [¿Qué tan precisa es la localización GNSS del SenseCAP T2000?](https://www.seeedstudio.com/blog/2026/01/19/how-accurate-is-the-sensecap-t2000-gnss-positioning/) + + +### Relacionado con la batería + +
+¿Cuál es la diferencia entre la batería del T2000-A/B y la del T2000-C? + +- **T2000-A/B** + - Alimentado por una **batería primaria de 8000mAh**. + - Diseñado para despliegues a largo plazo sin recarga. + +- **T2000-C** + - Alimentado por una **batería recargable de 4000mAh**. + - Equipado con un **panel solar de 0.5W** para funcionamiento continuo en exteriores. + - Adecuado para despliegues donde haya luz solar disponible y se necesite minimizar el mantenimiento. + +
+ + +
+¿Qué tan eficiente es la carga solar en el T2000-C? + +- El T2000-C utiliza un **panel solar de 0.5W con una batería recargable** para admitir un funcionamiento prolongado en exteriores. +- El panel solar puede generar **hasta unos 60mA de corriente de carga**, produciendo aproximadamente **60mAh** de energía por hora en buenas condiciones de luz solar (estos datos son solo de referencia). + +
+ + +
+¿Qué factores afectan la eficiencia de la carga solar? + +- El rendimiento de la carga solar puede variar según: + - La exposición e intensidad de la luz solar + - La orientación del panel y el ángulo de instalación + - Las sombras de objetos cercanos + - Polvo, suciedad o residuos en el panel solar + - Temperatura ambiente (la carga de la batería funciona entre 0–45°C) + +- Para obtener el mejor rendimiento, instala el dispositivo en un lugar con luz solar directa y revisa periódicamente la superficie del panel. + +
+ + +
+¿Puede el T2000-C funcionar de forma continua con energía solar? + +- En configuraciones de bajo consumo (como intervalos de subida más largos), la carga solar incluso puede mantener o aumentar el nivel de la batería durante el funcionamiento diario. +- Sin embargo, los intervalos de reporte frecuentes (por ejemplo, cada 1 minuto) pueden consumir más energía de la que el panel solar puede reponer. +- Para un análisis más detallado del rendimiento de la carga solar, consulta el siguiente blog: [¿Qué tan eficiente es la carga solar en el SenseCAP T2000‑C?](https://www.seeedstudio.com/blog/2026/01/19/how-efficient-is-the-solar-charging-on-the-sensecap-t2000-c/) + +
+ +La vida útil estimada de la batería puede calcularse utilizando la siguiente [Calculadora de vida útil de la batería](https://files.seeedstudio.com/products/SenseCAP/T2000_Tracker/SenseCAP_Tracker_Battery_Life_Calculator_T2000.xls). + + +## Soporte técnico y debate sobre el producto + +Gracias por elegir nuestros productos. Estamos aquí para ofrecerte diferentes tipos de soporte y garantizar que tu experiencia con nuestros productos sea lo más fluida posible. Ofrecemos varios canales de comunicación para adaptarnos a diferentes preferencias y necesidades. + +
+ + +
+ +
+ + +
\ No newline at end of file diff --git a/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/es_Payload_Format.md b/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/es_Payload_Format.md new file mode 100644 index 0000000000000..b01311690fe78 --- /dev/null +++ b/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/es_Payload_Format.md @@ -0,0 +1,522 @@ +--- +description: Formato de carga útil del rastreador SenseCAP T2000 +title: Formato de carga útil +keywords: + - Rastreador + - SenseCAP +image: https://files.seeedstudio.com/wiki/SenseCAP/SenseCAP_T2000_Tracker/SenseCAP_T2000_Tracker_QuickStart.webp +slug: /t2000_payload_format +last_update: + date: 3/12/2026 + author: Janet +createdAt: '2026-03-12' +updatedAt: '2026-03-12' +url: https://wiki.seeedstudio.com/es/t2000_payload_format/ +--- + +# Formato de carga útil + +## Análisis de paquetes de subida + +El protocolo de datos del rastreador proporciona diferentes paquetes para corresponder a distinta información, y el número de bytes de cada paquete puede variar. La estructura de la trama se muestra en la imagen siguiente. El contenido de la trama se envía en **orden de bytes big-endian**. + +|ID de datos|Valor de datos| +| - | :- | +|1 byte|50 bytes (máx.)| + +**Data ID**: Número de función.
+**Data Value**: Posición, datos de sensores y otra información. + +### Paquete de encendido (0x27) + +El paquete de encendido es enviado por el dispositivo inmediatamente después de arrancar. Contiene los parámetros de configuración actuales y el estado del dispositivo. El ID de trama es `0x27`, y la longitud total es de 46 bytes. + +| 0x27 | Byte2 | Byte3~4 | Byte5~6 | Byte7 | Byte8 | Byte9~10 | Byte11~12 | +| :--: | :---: | :-----: | :-----: | :--: | :--: | :------: | :-------: | +| ID | Nivel de batería | Versión de software | Versión de hardware | Modo de trabajo | Estrategia de posicionamiento | Intervalo de latido | Intervalo de subida en modo periódico | + +| Byte13~14 | Byte15 | Byte16 | Byte17 | Byte18 | Byte19~20 | Byte21~22 | +| :-------: | :----: | :----: | :----: | :----: | :-------: | :-------: | +| Intervalo de subida en modo de evento | Habilitar acelerómetro de 3 ejes | Habilitar alarma de desmontaje | Tiempo de espera de escaneo GNSS | Habilitar evento de movimiento | Umbral de movimiento de 3 ejes | Intervalo de subida en movimiento | + +| Byte23 | Byte24~25 | Byte26 | Byte27~28 | Byte29 | Byte30 | Byte31~46 | +| :----: | :-------: | :----: | :-------: | :----: | :----: | :-------: | +| Habilitar evento de inmovilidad | Tiempo de espera de inmovilidad | Habilitar evento de impacto | Umbral de impacto de 3 ejes | Tiempo de espera de escaneo iBeacon (s) | Bytes válidos del filtro UUID | Filtro UUID (16 bytes) | + +**Ejemplo de carga útil en bruto** + +`27 56 0100 0101 01 08 02d0 003c 003c 00 01 3c 00 001e 0005 00 0168 00 012c 03 00 00000000000000000000000000000000` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 27 | 27 es el ID del paquete | +| 2 | Nivel de batería | uint8 | 56 | `0x56` = 86(DEC)
El nivel de batería es 86% | +| 3~4 | Versión de software | uint16 | 0100 | `0x0100` = v1.0
La versión de software es v1.0 | +| 5~6 | Versión de hardware | uint16 | 0101 | `0x0101` = v1.1
La versión de hardware es v1.1 | +| 7 | Modo de trabajo | uint8 | 01 | 01 = Modo periódico
`00`: Modo de espera
`01`: Modo periódico
`02`: Modo de evento | +| 8 | Estrategia de posicionamiento | uint8 | 00 | 07 = 0x07, significa que el dispositivo usa la estrategia de posicionamiento Bluetooth + Wi‑Fi + GNSS
`00`: Solo GNSS
`01`: Solo Wi‑Fi
`02`: Wi‑Fi + GNSS
`03`: GNSS + Wi‑Fi
`04`: Solo Bluetooth
`05`: Bluetooth + Wi‑Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi‑Fi + GNSS
`08`: GNSS + Bluetooth | +| 9~10 | Intervalo de latido | uint16 | 02d0 | `0x02D0` = 720 minutos | +| 11~12 | Intervalo de subida en modo periódico | uint16 | 003c | `0x003C` = 60 minutos | +| 13~14 | Intervalo de subida en modo de evento | uint16 | 003c | `0x003C` = 60 minutos | +| 15 | Habilitar acelerómetro de 3 ejes | uint8 | 00 | `00`: Deshabilitar
`01`: Habilitar | +| 16 | Habilitar alarma de desmontaje | uint8 | 01 | `00`: Deshabilitar
`01`: Habilitar | +| 17 | Tiempo de espera de escaneo GNSS | uint8 | 3c | `0x3C` = 60 segundos | +| 18 | Habilitar evento de movimiento | uint8 | 00 | `00`: Deshabilitar
`01`: Habilitar | +| 19~20 | Umbral de movimiento de 3 ejes | uint16 | 001e | `0x001e` = 30 mg | +| 21~22 | Intervalo de subida en movimiento | uint16 | 0005 | `0x05` = 5 minutos | +| 23 | Habilitar evento de inmovilidad | uint8 | 00 | `0x00`: Deshabilitar
`0x01`: Habilitar | +| 24~25 | Tiempo de espera de inmovilidad | uint16 | 0168 | `0x0168` = 360 minutos | +| 26 | Habilitar evento de impacto | uint8 | 00 | `00`: Deshabilitar
`01`: Habilitar | +| 27~28 | Umbral de impacto de 3 ejes | uint16 | 012c | `0x012c` = 300 mg | +| 29 | Tiempo de espera de escaneo iBeacon (s) | uint8 | 03 | `0x03` = 3 segundos | +| 30 | Bytes válidos del filtro UUID | uint8 | 00 | Número de bytes válidos en el filtro UUID (0–16) | +| 31~46 | Filtro UUID | 16 bytes | 0000000000000000
0000000000000000 | Filtro UUID Bluetooth de 16 bytes. Solo los primeros N bytes (definidos por el byte30) son significativos | + +### Paquete de modo periódico (0x28) + +El paquete de parámetros de modo periódico contiene la configuración actual del modo de trabajo. El ID de trama es `0x28`, y la longitud total es de 30 bytes. + +| 0x28 | Byte2 | Byte3 | Byte4~5 | Byte6~7 | Byte8~9 | Byte10 | Byte11 | Byte12 | Byte13 | Byte14 | Byte15~30 | +| :--: | :---: | :---: | :-----: | :-----: | :-----: | :----: | :----: | :----: | :----: | :----: | :-------: | +| ID | Modo de trabajo | Estrategia de posicionamiento | Intervalo de latido | Intervalo de subida | Intervalo de subida en modo de evento | Habilitar acelerómetro de 3 ejes | Habilitar alarma de desmontaje | Tiempo de espera de escaneo GNSS | Tiempo de espera de escaneo iBeacon | Bytes válidos del filtro UUID | Filtro UUID (16 bytes) | + +**Ejemplo de carga útil en bruto** + +`28 01 07 02d0 003c 003c 01 00 3c 0a 10 00000000000000000000000000000000` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 28 | 28 es el ID del paquete | +| 2 | Modo de trabajo | uint8 | 01 | 01 = Modo periódico
`00`: Modo de espera
`01`: Modo periódico
`02`: Modo de evento | +| 3 | Estrategia de posicionamiento | uint8 | 07 | 07 = 0x07, significa que el dispositivo usa la estrategia de posicionamiento Bluetooth + Wi‑Fi + GNSS
`00`: Solo GNSS
`01`: Solo Wi‑Fi
`02`: Wi‑Fi + GNSS
`03`: GNSS + Wi‑Fi
`04`: Solo Bluetooth
`05`: Bluetooth + Wi‑Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi‑Fi + GNSS
`08`: GNSS + Bluetooth | +| 4~5 | Intervalo de latido | uint16 | 02d0 | `0x02D0` = 720 minutos | +| 6~7 | Intervalo de subida | uint16 | 003c | `0x003C` = 60 minutos | +| 8~9 | Intervalo de subida en modo de evento | uint16 | 003c | `0x003C` = 60 minutos
Cuando no se dispara ningún evento, los datos se subirán cada 60 minutos.
| +| 10 | Habilitar acelerómetro de 3 ejes | uint8 | 01 | `00`: Deshabilitar
`01`: Habilitar | +| 11 | Habilitar alarma de desmontaje | uint8 | 00 | `00`: Deshabilitar
`01`: Habilitar | +| 12 | Tiempo de espera de escaneo GNSS | uint8 | 3c | `0x3C` = 60 segundos | +| 13 | Tiempo de espera de escaneo iBeacon | uint8 | 0a | `0x0A` = 10 segundos | +| 14 | Bytes válidos del filtro UUID | uint8 | 10 | Número de bytes válidos en el filtro UUID (0–16) | +| 15~30 | Filtro UUID | 16 bytes | 0000000000000000
0000000000000000 | Filtro UUID Bluetooth de 16 bytes. Solo los primeros N bytes (definidos por el byte14) son significativos | + +### Paquete de modo de evento (0x29) + +El paquete de parámetros de evento contiene la configuración de los eventos de movimiento, inmovilidad e impacto. El ID de trama es `0x29`, y la longitud total es de 12 bytes. + +| 0x29 | Byte2 | Byte3~4 | Byte5~6 | Byte7 | Byte8~9 | Byte10 | Byte11~12 | +| :--: | :---: | :-----: | :-----: | :--: | :-----: | :----: | :-------: | +| ID | Habilitar evento de movimiento | Umbral de movimiento de 3 ejes | Intervalo de subida en movimiento | Habilitar evento de inmovilidad | Tiempo de espera de inmovilidad | Habilitar evento de impacto | Umbral de impacto de 3 ejes | + +**Ejemplo de carga útil en bruto** + +`29 01 0064 001e 01 012c 00 012c` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 29 | 29 es el ID del paquete | +| 2 | Habilitar evento de movimiento | uint8 | 01 | `00`: Deshabilitar
`01`: Habilitar | +| 3~4 | Umbral de movimiento de 3 ejes | uint16 | 0064 | `0x0064` = 100 mg | +| 5~6 | Intervalo de subida en movimiento | uint16 | 001e | `0x001E` = 30 minutos | +| 7 | Habilitar evento de inmovilidad | uint8 | 01 | `0x00`: Deshabilitar
`0x01`: Habilitar | +| 8~9 | Tiempo de espera de inmovilidad | uint16 | 012c | `0x012C` = 300 minutos | +| 10 | Habilitar evento de impacto | uint8 | 00 | `0x00`: Deshabilitar
`0x01`: Habilitar | +| 11~12 | Umbral de impacto de 3 ejes | uint16 | 0000 | `0x012c` = 300 mg | + +### Paquete de latido (0x2A) + +El paquete de latido es enviado periódicamente por el dispositivo para informar de su estado actual. Contiene información básica del dispositivo y estados de los sensores. El ID de trama es `0x2A`, y la longitud total es de 6 bytes. + +| 0x2A | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | +| :--: | :---: | :---: | :---: | :---: | :---: | +| ID | Nivel de batería | Modo de trabajo | Estrategia de posicionamiento | Habilitar acelerómetro de 3 ejes | Habilitar alarma de desmontaje | + +**Ejemplo de carga útil en bruto** + +`2a 56 01 07 01 00` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 2A | 2A es el ID del paquete | +| 2 | Nivel de batería | uint8 | 56 | `0x56` = 86(DEC)
El nivel de batería es 86% | +| 3 | Modo de trabajo | uint8 | 01 | 01 = Modo periódico
`00`: Modo de espera
`01`: Modo periódico
`02`: Modo de evento | +| 4 | Estrategia de posicionamiento | uint8 | 07 | 07 = 0x07, significa que el dispositivo usa la estrategia de posicionamiento Bluetooth + Wi‑Fi + GNSS
`00`: Solo GNSS
`01`: Solo Wi‑Fi
`02`: Wi‑Fi + GNSS
`03`: GNSS + Wi‑Fi
`04`: Solo Bluetooth
`05`: Bluetooth + Wi‑Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi‑Fi + GNSS
`08`: GNSS + Bluetooth | +| 5 | Habilitar acelerómetro de 3 ejes | uint8 | 01 | `00`: Deshabilitar
`01`: Habilitar | +| 6 | Habilitar alarma de desmontaje | uint8 | 00 | `00`: Deshabilitar
`01`: Habilitar | + +### Paquete de datos de ubicación GNSS (acelerómetro activado, 0x2B) + +El paquete de datos de ubicación GPS contiene datos de posicionamiento GNSS junto con información del acelerómetro y de la batería. El ID de trama es `0x2B`, y la longitud total es de 23 bytes. + +| 0x2B | Byte2~3 | Byte4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15~18 | Byte19~22 | Byte23 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :-------: | :------: | :------: | :---: | +| ID | Estado de evento | ID de movimiento | Marca de tiempo UTC | Acelerómetro X | Acelerómetro Y | Acelerómetro Z | Longitud | Latitud | Nivel de batería | + +**Ejemplo de carga útil en bruto** + +`2b 0100 00 694b3dc6 032f fffe 0241 06ca5098 01587ee4 62` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 2B | 2B es el ID del paquete | +| 2~3 | Estado de evento | uint16 | 0100 | `0x0100` = evento de desmontaje
Bit 0: falso
Bit 1: Evento de inicio de movimiento
Bit 2: Evento de fin de movimiento
Bit 3: Evento de inmovilidad
Bit 4: Evento de impacto
Bit 5: Evento de temperatura
Bit 6: Evento de luz
Bit 7: Evento SOS
Bit 8: Evento de pulsación única
Bit 9: Evento de desmontaje

Convertir a hexadecimal:
`0x0001`: Evento de inicio de movimiento
`0x0002`: Evento de fin de movimiento
`0x0004`: Evento de inmovilidad
`0x0008`: Evento de impacto
`0x0010`: Evento de temperatura
`0x0020`: Evento de luz
`0x0040`: Evento SOS
`0x0080`: Evento de pulsación única
`0x0100`: Evento de desmontaje | +| 4 | ID de movimiento | uint8 | 00 | `0`: No necesita registrarse como un movimiento específico.
`1~255`: Datos de posicionamiento reportados bajo el mismo estado de movimiento (el mismo ID se refiere al mismo movimiento) | +| 5~8 | Marca de tiempo UTC | uint32 | 694b3dc6 | `0x694B3DC6` = 1766538694(DEC) segundos

Convierte esto a hora UTC:
2025-12-24 01:11:34 | +| 9~10 | Acelerómetro X | int16 | 032f | `0x032F` = 815 mg | +| 11~12 | Acelerómetro Y | int16 | fffe | `0xFFFE` = -2 mg | +| 13~14 | Acelerómetro Z | int16 | 0241 | `0x0241` = 577 mg | +| 15~18 | Longitud | uint32 | 06ca5098 | `0x06CA5098` = 113,922,200 → 113.922200° | +| 19~22 | Latitud | uint32 | 01587ee4 | `0x01587EE4` = 22,576,868 → 22.576868° | +| 23 | Nivel de batería | uint8 | 62 | `0x62` = 98% | + +### Paquete de datos de ubicación Wi‑Fi (acelerómetro activado, 0x2C) + +El paquete de ubicación Wi‑Fi contiene resultados de escaneo Wi‑Fi junto con información del acelerómetro y de la batería. El ID de trama es `0x2C`, y la longitud total es dinámica según el número de puntos de acceso Wi‑Fi escaneados (23 + (n-1) * 7 bytes, donde n es el número de pares MAC‑RSSI). + +| 0x2C | Byte2~3 | Byte4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15 | Byte16 | Byte17+(n-1)*7 ~ Byte23+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :-------: | :---: | :---: | :---------------------------: | +| ID | Estado de evento | ID de movimiento | Marca de tiempo UTC | Acelerómetro X | Acelerómetro Y | Acelerómetro Z | Nivel de batería | Recuento MAC‑RSSI (n) | Pares MAC‑RSSI (n) | + +**Formato MAC‑RSSI** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| Dirección MAC (6 bytes) | RSSI (int8) | + +**Ejemplo de carga útil en bruto** + +`2c 0000 00 69685f82 0004 0015 03e5 64 05 107c61841bf8 e4 3447d468f627 e1 a4ba70bc229d d3 9483c46d5dfc d2 4c10d567b467 d0` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 2C | 2C es el ID del paquete | +| 2~3 | Estado de evento | uint16 | 0000 |`0x0000` = No se han activado eventos
Bit 0: falso
Bit 1: Evento de inicio de movimiento
Bit 2: Evento de fin de movimiento
Bit 3: Evento de inmovilidad
Bit 4: Evento de impacto
Bit 5: Evento de temperatura
Bit 6: Evento de luz
Bit 7: Evento SOS
Bit 8: Evento de pulsación única
Bit 9: Evento de desensamblado

Convertir a hexadecimal:
`0x0001`: Evento de inicio de movimiento
`0x0002`: Evento de fin de movimiento
`0x0004`: Evento de inmovilidad
`0x0008`: Evento de impacto
`0x0010`: Evento de temperatura
`0x0020`: Evento de luz
`0x0040`: Evento SOS
`0x0080`: Evento de pulsación única
`0x0100`: Evento de desensamblado| +| 4 | ID de movimiento | uint8 | 00 | `0`: No necesita registrarse como un movimiento específico.
`1~255`: Datos de posicionamiento reportados bajo el mismo estado de movimiento (el mismo ID se refiere al mismo movimiento) | +| 5~8 | Marca de tiempo UTC | uint32 | 69685f82 | `0x69685F82` = 1768447874(DEC) segundos

Convierte a hora UTC:
2026-01-15 03:31:14 | +| 9~10 | Acelerómetro X | int16 | 0004 | `0x0004` = 4 mg | +| 11~12 | Acelerómetro Y | int16 | 0015 | `0x0015` = 21 mg | +| 13~14 | Acelerómetro Z | int16 | 03e5 | `0x03E5` = 997 mg | +| 15 | Nivel de batería | uint8 | 64 | `0x64` = 100% | +| 16 | Recuento MAC‑RSSI (n) | uint8 | 05 | Número de puntos de acceso Wi‑Fi detectados (n = 5) | +| 17~23 | Par MAC‑RSSI 1 | 7 bytes | 107c61841bf8 e4 | MAC: `10:7C:61:84:1B:F8`, RSSI: `0xE4` = -28 (int8) | +| 24~30 | Par MAC‑RSSI 2 | 7 bytes | 3447d468f627 e1 | MAC: `34:47:D4:68:F6:27`, RSSI: `0xE1` = -31 (int8) | +| 31~37 | Par MAC‑RSSI 3 | 7 bytes | a4ba70bc229d d3 | MAC: `A4:BA:70:BC:22:9D`, RSSI: `0xD3` = -45 (int8) | +| 38~44 | Par MAC‑RSSI 4 | 7 bytes | 9483c46d5dfc d2 | MAC: `94:83:C4:6D:5D:FC`, RSSI: `0xD2` = -46 (int8) | +| 45~51 | Par MAC‑RSSI 5 | 7 bytes | 4c10d567b467 d0 | MAC: `4C:10:D5:67:B4:67`, RSSI: `0xD0` = -48 (int8) | + +### Paquete de datos de ubicación BLE (acelerómetro activado, 0x2D) + +El paquete de ubicación BLE contiene resultados de escaneo Bluetooth junto con información del acelerómetro y de la batería. El ID de trama es `0x2D`, y la longitud total es dinámica según el número de dispositivos Bluetooth escaneados (23 + (n-1) * 7 bytes, donde n es el número de pares MAC‑RSSI, máximo n = 5). + +| 0x2D | Byte2~3 | Byte4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15 | Byte16 | Byte17+(n-1)*7 ~ Byte23+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :-------: | :---: | :---: | :---------------------------: | +| ID | Estado de evento | ID de movimiento | Marca de tiempo UTC | Acelerómetro X | Acelerómetro Y | Acelerómetro Z | Nivel de batería | Recuento MAC‑RSSI (n) | Pares MAC‑RSSI (n) | + +**Formato MAC‑RSSI** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| Dirección MAC (6 bytes) | RSSI (int8) | + +**Ejemplo de carga útil en bruto** + +`2d 0000 00 69686032 fff9 0015 03df 64 05 c30000564b3b ce c20303003f00 ce 588c81a0fbf2 cc c20303003f03 cb c30000564af2 c7` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 2D | 2D es el ID del paquete | +| 2~3 | Estado de evento | uint16 | 0000 |`0x0000` = No se han activado eventos
Bit 0: falso
Bit 1: Evento de inicio de movimiento
Bit 2: Evento de fin de movimiento
Bit 3: Evento de inmovilidad
Bit 4: Evento de impacto
Bit 5: Evento de temperatura
Bit 6: Evento de luz
Bit 7: Evento SOS
Bit 8: Evento de pulsación única
Bit 9: Evento de desensamblado

Convertir a hexadecimal:
`0x0001`: Evento de inicio de movimiento
`0x0002`: Evento de fin de movimiento
`0x0004`: Evento de inmovilidad
`0x0008`: Evento de impacto
`0x0010`: Evento de temperatura
`0x0020`: Evento de luz
`0x0040`: Evento SOS
`0x0080`: Evento de pulsación única
`0x0100`: Evento de desensamblado| +| 4 | ID de movimiento | uint8 | 00 | `0`: No necesita registrarse como un movimiento específico.
`1~255`: Datos de posicionamiento reportados bajo el mismo estado de movimiento (el mismo ID se refiere al mismo movimiento) | +| 5~8 | Marca de tiempo UTC | uint32 | 69686032 | `0x69686032` = 1768448050(DEC) segundos

Convierte a hora UTC:
2026-01-15 03:34:10 | +| 9~10 | Acelerómetro X | int16 | fff9 | `0xFFF9` = -7 mg | +| 11~12 | Acelerómetro Y | int16 | 0015 | `0x0015` = 21 mg | +| 13~14 | Acelerómetro Z | int16 | 03df | `0x03DF` = 991 mg | +| 15 | Nivel de batería | uint8 | 64 | `0x64` = 100% | +| 16 | Recuento MAC‑RSSI (n) | uint8 | 05 | Número de dispositivos Bluetooth detectados (n = 5, máximo 5) | +| 17~23 | Par MAC‑RSSI 1 | 7 bytes | c30000564b3b ce | MAC: `C3:00:00:56:4B:3B`, RSSI: `0xCE` = -50 (int8) | +| 24~30 | Par MAC‑RSSI 2 | 7 bytes | c20303003f00 ce | MAC: `C2:03:03:00:3F:00`, RSSI: `0xCE` = -50 (int8) | +| 31~37 | Par MAC‑RSSI 3 | 7 bytes | 588c81a0fbf2 cc | MAC: `58:8C:81:A0:FB:F2`, RSSI: `0xCC` = -52 (int8) | +| 38~44 | Par MAC‑RSSI 4 | 7 bytes | c20303003f03 cb | MAC: `C2:03:03:00:3F:03`, RSSI: `0xCB` = -53 (int8) | +| 45~51 | Par MAC‑RSSI 5 | 7 bytes | c30000564af2 c7 | MAC: `C3:00:00:56:4A:F2`, RSSI: `0xC7` = -57 (int8) | + +### Paquete de datos de ubicación GNSS (acelerómetro desactivado, 0x2E) + +El paquete de datos de ubicación GNSS contiene datos de posicionamiento GPS junto con información de la batería. El ID de trama es `0x2E`, y la longitud total es de 17 bytes. + +| 0x2E | Byte2~3 | Byte4 | Byte5~8 | Byte9~12 | Byte13~16 | Byte17 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :----: | +| ID | Estado de evento | ID de movimiento | Marca de tiempo UTC | Longitud | Latitud | Nivel de batería | + +**Ejemplo de carga útil en bruto** + +`2e 0100 01 64f1a2b3 06ca5098 01587ee4 62` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 2E | 2E es el ID del paquete | +| 2~3 | Estado de evento | uint16 | 0000 |`0x0000` = No se han activado eventos
Bit 0: falso
Bit 1: Evento de inicio de movimiento
Bit 2: Evento de fin de movimiento
Bit 3: Evento de inmovilidad
Bit 4: Evento de impacto
Bit 5: Evento de temperatura
Bit 6: Evento de luz
Bit 7: Evento SOS
Bit 8: Evento de pulsación única
Bit 9: Evento de desensamblado

Convertir a hexadecimal:
`0x0001`: Evento de inicio de movimiento
`0x0002`: Evento de fin de movimiento
`0x0004`: Evento de inmovilidad
`0x0008`: Evento de impacto
`0x0010`: Evento de temperatura
`0x0020`: Evento de luz
`0x0040`: Evento SOS
`0x0080`: Evento de pulsación única
`0x0100`: Evento de desensamblado| +| 4 | ID de movimiento | uint8 | 00 | `0`: No necesita registrarse como un movimiento específico.
`1~255`: Datos de posicionamiento reportados bajo el mismo estado de movimiento (el mismo ID se refiere al mismo movimiento) | +| 5~8 | Marca de tiempo UTC | uint32 | 64f1a2b3 | `0x64f1a2b3` = 1693557427(DEC) segundos

Convierte a hora UTC:
2023-09-01 08:37:07 | +| 9~12 | Longitud | uint32 | 06ca5098 | `0x06CA5098` = 113,922,200 → 113.922200° | +| 13~16 | Latitud | uint32 | 01587ee4 | `0x01587EE4` = 22,576,868 → 22.576868° | +| 17 | Nivel de batería | uint8 | 62 | `0x62` = 98% | + +### Paquete de datos de ubicación Wi‑Fi (acelerómetro desactivado, 0x2F) + +El paquete de datos de ubicación Wi‑Fi contiene resultados de escaneo Wi‑Fi junto con información de la batería. El ID de trama es `0x2F`, y la longitud total es dinámica según el número de puntos de acceso Wi‑Fi escaneados (17 + (n-1) * 7 bytes, donde n es el número de pares MAC‑RSSI, máximo n = 5). + +| 0x2F | Byte2~3 | Byte4 | Byte5~8 | Byte9 | Byte10 | Byte11+(n-1)*7 ~ Byte16+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :---: | :----: | :---------------------------: | +| ID | Estado de evento | ID de movimiento | Marca de tiempo UTC | Nivel de batería | Recuento MAC‑RSSI (n) | Pares MAC‑RSSI (n) | + +**Formato MAC‑RSSI** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| Dirección MAC (6 bytes) | RSSI (int8) | + +**Ejemplo de carga útil en bruto** + +`2f 0000 00 69685f82 64 05 107c61841bf8 e4 3447d468f627 e1 a4ba70bc229d d3 9483c46d5dfc d2 4c10d567b467 d0` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 2F | 2F es el ID del paquete | +| 2~3 | Estado de evento | uint16 | 0000 |`0x0000` = No se han activado eventos
Bit 0: falso
Bit 1: Evento de inicio de movimiento
Bit 2: Evento de fin de movimiento
Bit 3: Evento de inmovilidad
Bit 4: Evento de impacto
Bit 5: Evento de temperatura
Bit 6: Evento de luz
Bit 7: Evento SOS
Bit 8: Evento de pulsación única
Bit 9: Evento de desensamblado

Convertir a hexadecimal:
`0x0001`: Evento de inicio de movimiento
`0x0002`: Evento de fin de movimiento
`0x0004`: Evento de inmovilidad
`0x0008`: Evento de impacto
`0x0010`: Evento de temperatura
`0x0020`: Evento de luz
`0x0040`: Evento SOS
`0x0080`: Evento de pulsación única
`0x0100`: Evento de desensamblado| +| 4 | ID de movimiento | uint8 | 00 | `0`: No necesita registrarse como un movimiento específico.
`1~255`: Datos de posicionamiento reportados bajo el mismo estado de movimiento (el mismo ID se refiere al mismo movimiento) | +| 5~8 | Marca de tiempo UTC | uint32 | 69685f82 | `0x69685F82` = 1768447874(DEC) segundos

Convierte a hora UTC:
2026-01-15 03:31:14 | +| 9 | Nivel de batería | uint8 | 64 | `0x64` = 100% | +| 10 | Recuento MAC‑RSSI (n) | uint8 | 05 | Número de puntos de acceso Wi‑Fi detectados (n = 5, máximo 5) | +| 11~17 | Par MAC‑RSSI 1 | 7 bytes | 107c61841bf8 e4 | MAC: `10:7C:61:84:1B:F8`,
RSSI: `0xE4` = -28 (int8) | +| 18~24 | Par MAC‑RSSI 2 | 7 bytes | 3447d468f627 e1 | MAC: `34:47:D4:68:F6:27`,
RSSI: `0xE1` = -31 (int8) | +| 25~31 | Par MAC‑RSSI 3 | 7 bytes | a4ba70bc229d d3 | MAC: `A4:BA:70:BC:22:9D`,
RSSI: `0xD3` = -45 (int8) | +| 32~38 | Par MAC‑RSSI 4 | 7 bytes | 9483c46d5dfc d2 | MAC: `94:83:C4:6D:5D:FC`,
RSSI: `0xD2` = -46 (int8) | +| 39~45 | Par MAC‑RSSI 5 | 7 bytes | 4c10d567b467 d0 | MAC: `4C:10:D5:67:B4:67`,
RSSI: `0xD0` = -48 (int8) | + +### Paquete de datos de ubicación BLE (acelerómetro desactivado, 0x30) + +El paquete de datos de ubicación BLE contiene resultados de escaneo Bluetooth junto con información de la batería. El ID de trama es `0x30`, y la longitud total es dinámica según el número de dispositivos Bluetooth escaneados (17 + (n-1) * 7 bytes, donde n es el número de pares MAC-RSSI, máximo n = 5). + +| 0x30 | Byte2~3 | Byte4 | Byte5~8 | Byte9 | Byte10 | Byte11+(n-1)*7 ~ Byte16+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :---: | :----: | :---------------------------: | +| ID | Estado de evento | ID de movimiento | Marca de tiempo UTC | Nivel de batería | Recuento MAC-RSSI (n) | Pares MAC-RSSI (n) | + +**Formato MAC-RSSI** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| Dirección MAC (6 bytes) | RSSI (int8) | + +**Ejemplo de carga útil en bruto** + +`30 0000 00 69686032 64 05 c30000564b3b ce c20303003f00 ce 588c81a0fbf2 cc c20303003f03 cb c30000564af2 c7` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 30 | 30 es el ID del paquete | +| 2~3 | Estado de evento | uint16 | 0000 |`0x0000` = No se han activado eventos
Bit 0: falso
Bit 1: Evento de inicio de movimiento
Bit 2: Evento de fin de movimiento
Bit 3: Evento de inmovilidad
Bit 4: Evento de impacto
Bit 5: Evento de temperatura
Bit 6: Evento de luz
Bit 7: Evento SOS
Bit 8: Evento de pulsación única
Bit 9: Evento de desensamblado

Convertir a hexadecimal:
`0x0001`: Evento de inicio de movimiento
`0x0002`: Evento de fin de movimiento
`0x0004`: Evento de inmovilidad
`0x0008`: Evento de impacto
`0x0010`: Evento de temperatura
`0x0020`: Evento de luz
`0x0040`: Evento SOS
`0x0080`: Evento de pulsación única
`0x0100`: Evento de desensamblado| +| 4 | ID de movimiento | uint8 | 00 | `0`: No necesita registrarse como un movimiento específico.
`1~255`: Datos de posicionamiento reportados bajo el mismo estado de movimiento (el mismo ID se refiere al mismo movimiento) | +| 5~8 | Marca de tiempo UTC | uint32 | 69686032 | `0x69686032` = 1768448050(DEC) segundos

Convierte esto a hora UTC:
2026-01-15 03:34:10 | +| 9 | Nivel de batería | uint8 | 64 | `0x64` = 100% | +| 10 | Recuento MAC-RSSI (n) | uint8 | 05 | Número de dispositivos Bluetooth detectados (n = 5, máximo 5) | +| 11~17 | Par MAC-RSSI 1 | 7 bytes | c30000564b3b ce | MAC: `C3:00:00:56:4B:3B`,
RSSI: `0xCE` = -50 (int8) | +| 18~24 | Par MAC-RSSI 2 | 7 bytes | c20303003f00 ce | MAC: `C2:03:03:00:3F:00`,
RSSI: `0xCE` = -50 (int8) | +| 25~31 | Par MAC-RSSI 3 | 7 bytes | 588c81a0fbf2 cc | MAC: `58:8C:81:A0:FB:F2`,
RSSI: `0xCC` = -52 (int8) | +| 32~38 | Par MAC-RSSI 4 | 7 bytes | c20303003f03 cb | MAC: `C2:03:03:00:3F:03`,
RSSI: `0xCB` = -53 (int8) | +| 39~45 | Par MAC-RSSI 5 | 7 bytes | c30000564af2 c7 | MAC: `C3:00:00:56:4A:F2`,
RSSI: `0xC7` = -57 (int8) | + +### Paquete de estado de posicionamiento con acelerómetro (0x31) + +El paquete de estado de posicionamiento contiene el estado de posicionamiento junto con datos del acelerómetro, estado de evento e información de la batería. El ID de trama es `0x31`, y la longitud total es de 15 bytes. + +| 0x31 | Byte2 | Byte3~4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15 | +| :--: | :---: | :-----: | :-----: | :------: | :-------: | :-------: | :---: | +| ID | Estado de posicionamiento | Estado de evento | Marca de tiempo UTC | Acelerómetro X | Acelerómetro Y | Acelerómetro Z | Nivel de batería | + +**Ejemplo de carga útil en bruto** + +`31 00 0100 694b3db0 003a 039d fe84 62` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 31 | 31 es el ID del paquete | +| 2 | Estado de posicionamiento | uint8 | 00 |`0x00`: localización correcta.
`0x01`: El escaneo GNSS agotó el tiempo de espera.
`0x02`: El escaneo Wi‑Fi agotó el tiempo de espera.
`0x03`: El escaneo Wi‑Fi + GNSS agotó el tiempo de espera.
`0x04`: El escaneo GNSS + Wi‑Fi agotó el tiempo de espera.
`0x05`: El escaneo Bluetooth agotó el tiempo de espera.
`0x06`: El escaneo Bluetooth + Wi‑Fi agotó el tiempo de espera.
`0x07`: El escaneo Bluetooth + GNSS agotó el tiempo de espera.
`0x08`: El escaneo Bluetooth + Wi‑Fi + GNSS agotó el tiempo de espera.
`0x09`: El servidor de localización no pudo analizar la ubicación GNSS.
`0x0A`: El servidor de localización no pudo analizar la ubicación Wi‑Fi.
`0x0B`: El servidor de localización no pudo analizar la ubicación Bluetooth.
`0x0C`: No se pudo analizar la ubicación debido a la baja precisión.
`0x0D`: Falló la sincronización de hora.
`0x0E`: Falló debido al Almanaque antiguo.
`0x0F`: El escaneo GNSS + Bluetooth agotó el tiempo de espera. | +| 3~4 | Estado de evento | uint16 | 0000 |`0x0000` = No se han activado eventos
Bit 0: falso
Bit 1: Evento de inicio de movimiento
Bit 2: Evento de fin de movimiento
Bit 3: Evento de inmovilidad
Bit 4: Evento de impacto
Bit 5: Evento de temperatura
Bit 6: Evento de luz
Bit 7: Evento SOS
Bit 8: Evento de pulsación única
Bit 9: Evento de desensamblado

Convertir a hexadecimal:
`0x0001`: Evento de inicio de movimiento
`0x0002`: Evento de fin de movimiento
`0x0004`: Evento de inmovilidad
`0x0008`: Evento de impacto
`0x0010`: Evento de temperatura
`0x0020`: Evento de luz
`0x0040`: Evento SOS
`0x0080`: Evento de pulsación única
`0x0100`: Evento de desensamblado | +| 5~8 | Marca de tiempo UTC | uint32 | 694B3DB0 | `0x694B3DB0` = 1766538672(DEC) segundos

Convierte esto a hora UTC:
2025-12-24 01:11:12 | +| 9~10 | Acelerómetro X | int16 | 003a | `0x003A` = 58 mg | +| 11~12 | Acelerómetro Y | int16 | 039d | `0x039D` = 925 mg | +| 13~14 | Acelerómetro Z | int16 | fe84 | `0xFE84` = -380 mg | +| 15 | Nivel de batería | uint8 | 62 | `0x62` = 98% | + +### Paquete de estado de posicionamiento (acelerómetro desactivado, 0x32) + +El paquete de estado de posicionamiento contiene el estado de posicionamiento junto con el estado de evento y la información de la batería. El ID de trama es `0x32`, y la longitud total es de 9 bytes. + +| 0x32 | Byte2 | Byte3~4 | Byte5~8 | Byte9 | +| :--: | :---: | :-----: | :-----: | :---: | +| ID | Estado de posicionamiento | Estado de evento | Marca de tiempo UTC | Nivel de batería | + +**Ejemplo de carga útil en bruto** + +`32 00 0100 694b3db0 62` + +| Byte | Valor | Tipo | Datos en bruto | Descripción | +| :---: | :--- | :---: | :---: | :--- | +| 1 | ID de trama | uint8 | 32 | 32 es el ID del paquete | +| 2 | Estado de posicionamiento | uint8 | 00 |`0x00`: localización correcta.
`0x01`: El escaneo GNSS agotó el tiempo de espera.
`0x02`: El escaneo Wi‑Fi agotó el tiempo de espera.
`0x03`: El escaneo Wi‑Fi + GNSS agotó el tiempo de espera.
`0x04`: El escaneo GNSS + Wi‑Fi agotó el tiempo de espera.
`0x05`: El escaneo Bluetooth agotó el tiempo de espera.
`0x06`: El escaneo Bluetooth + Wi‑Fi agotó el tiempo de espera.
`0x07`: El escaneo Bluetooth + GNSS agotó el tiempo de espera.
`0x08`: El escaneo Bluetooth + Wi‑Fi + GNSS agotó el tiempo de espera.
`0x09`: El servidor de localización no pudo analizar la ubicación GNSS.
`0x0A`: El servidor de localización no pudo analizar la ubicación Wi‑Fi.
`0x0B`: El servidor de localización no pudo analizar la ubicación Bluetooth.
`0x0C`: No se pudo analizar la ubicación debido a la baja precisión.
`0x0D`: Falló la sincronización de hora.
`0x0E`: Falló debido al Almanaque antiguo.
`0x0F`: El escaneo GNSS + Bluetooth agotó el tiempo de espera. | +| 3~4 | Estado de evento | uint16 | 0100 | `0x0000` = No se han activado eventos
Bit 0: falso
Bit 1: Evento de inicio de movimiento
Bit 2: Evento de fin de movimiento
Bit 3: Evento de inmovilidad
Bit 4: Evento de impacto
Bit 5: Evento de temperatura
Bit 6: Evento de luz
Bit 7: Evento SOS
Bit 8: Evento de pulsación única
Bit 9: Evento de desensamblado

Convertir a hexadecimal:
`0x0001`: Evento de inicio de movimiento
`0x0002`: Evento de fin de movimiento
`0x0004`: Evento de inmovilidad
`0x0008`: Evento de impacto
`0x0010`: Evento de temperatura
`0x0020`: Evento de luz
`0x0040`: Evento SOS
`0x0080`: Evento de pulsación única
`0x0100`: Evento de desensamblado | +| 5~8 | Marca de tiempo UTC | uint32 | 694B3DB0 | `0x694B3DB0` = 1766538672(DEC) segundos

Convierte esto a hora UTC:
2025-12-24 01:11:12 | +| 9 | Nivel de batería | uint8 | 62 | `0x62` = 98% | + +## Paquete de enlace descendente, FPort=5 + +El rastreador es compatible con LoRaWAN para enviar por enlace descendente algunos comandos para ajustar parámetros. Si el dispositivo está en hibernación, el comando de enlace descendente surtirá efecto la próxima vez que el dispositivo se despierte para subir datos. + +Debido a LoRaWAN Clase A, donde las ventanas de enlace descendente solo se abren después de un enlace ascendente, los comandos no son en tiempo real. Por ejemplo, si el intervalo de reporte se establece en 10 minutos, puede tardar hasta 10 minutos para que el dispositivo reciba el comando de enlace descendente durante su próxima ventana de transmisión. + +**Nota: FPort=5** + +### Paquete de solicitud de estado del dispositivo (0x8F) + +|0x8F| +| - | +|ID| + +Ejemplo: + +8F: Solicita el último paquete de estado y ubicación del dispositivo. + +### Configuración del modo de trabajo y estrategia de posicionamiento (0x90) + +|0x90|Byte2|Byte3|Byte4~5|Byte6~7|Byte8~9| +| - | :- | :- | :- | :- | :- | +|ID|Modo de trabajo|Estrategia de posicionamiento|Intervalo de latido|Intervalo de enlace ascendente en modo periódico|Intervalo de enlace ascendente en modo de evento| + +|Byte10|Byte11|Byte12|Byte13|Byte14|Byte15~30| +| - | - | - | - | - | :- | +|Habilitar acelerómetro de 3 ejes|Habilitar alarma de desensamblado|Tiempo de espera de escaneo GNSS (s)|Tiempo de espera de escaneo iBeacon (s)|Byte válido de filtro UUID|Filtro UUID| + +Nota: +Unidad de Intervalo de latido / Intervalo de enlace ascendente en modo periódico / Intervalo de enlace ascendente en modo de evento: **minutos** + +Ejemplo: + +`90 01 01 02d0 0014 0005 01 01 1e 0a 10 00000000000000000000000000000000` + + +|**Byte**|**Valor**|**Tipo**|**Datos en bruto**|**Descripción**| +| - | - | - | - | - | +|1|ID de trama|uint8|90|90 es el ID del paquete| +|2|Modo de trabajo|uint8|01|01 = Modo periódico
`00`: Modo de espera
`01`: Modo periódico
`02`: Modo de evento| +|3|Estrategia de posicionamiento|uint8|01|`00`: Solo GNSS
`01`: Solo Wi‑Fi
`02`: Wi‑Fi + GNSS
`03`: GNSS + Wi‑Fi
`04`: Solo Bluetooth
`05`: Bluetooth + Wi‑Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi‑Fi + GNSS
`08`: GNSS + Bluetooth | +|4~5|Intervalo de latido | uint16 | 02d0 | `0x02D0` = 720 minutos| +|6~7|Intervalo de enlace ascendente en modo periódico|uint16|0014|`0x0014` = 20 minutos | +|8~9|Intervalo de enlace ascendente en modo de evento|uint16|0005|`0x0005` = 5 minutos
Cuando no se activa ningún evento, los datos se subirán cada 5 minutos.
| +|10|Habilitar acelerómetro de 3 ejes|uint8|01|`00`: Desactivar
`01`: Activar| +|11|Habilitar alarma de desensamblado|uint8|01|`00`: Desactivar
`01`: Activar| +|12|Tiempo de espera de escaneo GNSS|uint8|1E|`0x1E` = 30 segundos | +|13|Tiempo de espera de escaneo iBeacon|uint8|0A|`0x0A` = 10 segundos | +|14|Bytes válidos de filtro UUID|uint8|10| Número de bytes válidos en el filtro UUID (0–16)| +|15~30|Filtro UUID| 16 bytes | 0000000000000000
0000000000000000 | Filtro UUID Bluetooth de 16 bytes. Solo los primeros N bytes (definidos por el byte30) son significativos| + + +### Configuración del umbral del modo de evento (0x91) + +|0x91|Byte2|Byte3~4|Byte5~6|Byte7|Byte8~9| +| - | :- | :- | :- | :- | :- | +|ID|Habilitar evento de movimiento|Umbral de movimiento de 3 ejes|Intervalo de subida en movimiento|Habilitar evento de inmovilidad|Tiempo de espera de inmovilidad| + +|Byte10|Byte11~12| +| - | :- | +|Habilitar evento de impacto|Umbral de impacto de 3 ejes| + + +Ejemplo: + +`91 01 001e 0005 01 01 2c` + +|**Byte**|**Valor**|**Tipo**|**Datos en bruto**|**Descripción**| +| - | - | - | - | - | +|1|ID de trama|uint8|91|91 es el ID del paquete| +|2|Habilitar evento de movimiento|uint8|01|`00`: Disable
`01`: Enable| +|3~4|Umbral de movimiento de 3 ejes|uint16|001e|`0x001E` = 30 mg
Cuando la aceleración supera 30 mg, el dispositivo determina que está en movimiento
| +|5~6|Intervalo de subida en movimiento|uint16|0005|`0x0005` = 5 minutes
Cuando se detecta movimiento, el intervalo de informe es de 5 minutos
| +|7|Habilitar evento de inmovilidad|uint8|01|`00`: Disable
`01`: Enable| +|8~9|Tiempo de espera de inmovilidad|uint16|012c|`0x012C` = 300 minutes
Si el dispositivo permanece inmóvil durante más de 300 minutos, se activará un evento de inmovilidad
| +|10|Habilitar evento de impacto|uint8|01|`00`: Disable
`01`: Enable| +|11~12|Umbral de impacto de 3 ejes|uint16|012c|`0x012C` = 300 mg
Cuando la aceleración supera 300 mg, se activará el evento de impacto
| + +### Paquete de solicitud de estado del dispositivo (0x92) + +|0x92| +| - | +|ID| + +Ejemplo: + +92: Forzar una fijación de ubicación GNSS. + +### Configuración del modo de trabajo, estrategia de posicionamiento y umbral del modo de evento (0x97) + +|0x97|Byte2|Byte3|Byte4~5|Byte6~7|Byte8~9| +| - | :- | :- | :- | :- | :- | +|ID|Modo de trabajo|Estrategia de posicionamiento|Intervalo de latido|Intervalo de subida en modo periódico|Intervalo de subida en modo de evento| + +|Byte10|Byte11|Byte12|Byte13|Byte14|Byte15~30| +| - | :- | :- | :- | :- | :- | +|Habilitar acelerómetro de 3 ejes|Habilitar alarma de desmontaje|Tiempo de espera de escaneo GNSS|Tiempo de espera de escaneo iBeacon|Bytes válidos del filtro UUID|Filtro UUID| + +#### Configuración de eventos de movimiento +|Byte31|Byte32~33|Byte34~35| +| - | :- | :- | +|Habilitar evento de movimiento|Umbral de movimiento de 3 ejes|Intervalo de subida en movimiento| + +#### Configuración de eventos de inmovilidad +|Byte36|Byte37~38| +| - | :- | +|Habilitar evento de inmovilidad|Tiempo de espera de inmovilidad| + + +#### Configuración de eventos de impacto +|Byte39|Byte40~41| +| - | :- | +|Habilitar evento de impacto|Umbral de impacto de 3 ejes| + +Ejemplo: + +`97 01 02 003c 001e 000a 01 01 0a 05 10 00000000000000000000000000000000 01 001e 0005 01 012c 01 012c` + +|**Byte**|**Valor**|**Tipo**|**Datos en bruto**|**Descripción**| +| - | - | - | - | - | +|1|ID de trama|uint8|97|97 es el ID del paquete| +|2|Modo de trabajo|uint8|01|`00`: Standby Mode
`01`: Periodic Mode
`02`: Event Mode| +|3|Estrategia de posicionamiento|uint8|02|`00`: Only GNSS
`01`: Only Wi-Fi
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: Only Bluetooth
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +|4~5|Intervalo de latido|uint16|003c|`0x003C` = 60 seconds| +|6~7|Intervalo de subida en modo periódico|uint16|001e|`0x001E` = 30 seconds| +|8~9|Intervalo de subida en modo de evento|uint16|000a|`0x000A` = 10 minutes
Cuando no se activa ningún evento, los datos se subirán cada 10 minutos.
| +|10|Habilitar acelerómetro de 3 ejes|uint8|01|`00`: Disable
`01`: Enable| +|11|Habilitar alarma de desmontaje|uint8|01|`00`: Disable
`01`: Enable| +|12|Tiempo de espera de escaneo GNSS|uint8|0a|`0x0A` = 10 seconds| +|13|Tiempo de espera de escaneo iBeacon|uint8|05|`0x05` = 5 seconds| +|14|Bytes válidos del filtro UUID|uint8|10|`0x10` = 16 bytes| +|15~30|Filtro UUID|byte[16]|0000000000000000
0000000000000000|Valor del filtro UUID (16 bytes)
| +|31|Habilitar evento de movimiento|uint8|01|`00`: Disable
`01`: Enable| +|32~33|Umbral de movimiento de 3 ejes|uint16|001e|`0x001E` = 30 mg | +|34~35|Intervalo de subida en movimiento|uint16|0005|`0x0005` = 5 minutes
Cuando se detecta movimiento, el intervalo de informe es de 5 minutos| +|36|Habilitar evento de inmovilidad|uint8|01|`00`: Disable
`01`: Enable| +|37~38|Tiempo de espera de inmovilidad|uint16|012c|`0x012C` = 300 minutes | +|39|Habilitar evento de impacto|uint8|01|`00`: Disable
`01`: Enable| +|40~41|Umbral de impacto de 3 ejes|uint16|012c|`0x012C` = 300 mg | + +## Soporte técnico y debate sobre el producto + +Gracias por elegir nuestros productos. Estamos aquí para ofrecerte diferentes tipos de soporte y garantizar que tu experiencia con nuestros productos sea lo más fluida posible. Ofrecemos varios canales de comunicación para adaptarnos a diferentes preferencias y necesidades. + +
+ + +
+ +
+ + +
\ No newline at end of file diff --git a/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/es_SenseCAP_T2000_intro.md b/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/es_SenseCAP_T2000_intro.md index c23f3540fcd21..02f84454d590c 100644 --- a/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/es_SenseCAP_T2000_intro.md +++ b/sites/es/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/es_SenseCAP_T2000_intro.md @@ -1,32 +1,34 @@ --- -description: SenseCAP T2000 Tracker -title: SenseCAP T2000 Tracker +description: Rastreador SenseCAP T2000 +title: Rastreador SenseCAP T2000 keywords: - - Tracker + - Rastreador - SenseCAP image: https://files.seeedstudio.com/wiki/wiki-platform/S-tempor.png slug: /sensecap_t2000_tracker last_update: - date: 1/28/2026 + date: 3/12/2026 author: Janet -createdAt: '2025-12-01' -updatedAt: '2026-03-03' +createdAt: '2025-11-27' +updatedAt: '2026-03-12' url: https://wiki.seeedstudio.com/es/sensecap_t2000_tracker/ ---

pir

-[**SenseCAP T2000 Tracker**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html), un rastreador de activos LoRaWAN® de grado industrial, soporta posicionamiento GNSS, Bluetooth y Wi-Fi para un seguimiento confiable en entornos interiores y exteriores. Cuenta con protección IP67, un acelerómetro de 3 ejes integrado que detecta el estado de movimiento, y un botón anti-manipulación que activa una alarma de máxima prioridad si el dispositivo es removido. El T2000-A y T2000-B soportan operación de batería de larga duración, mientras que el T2000-C alimentado por energía solar con batería recargable asegura uso continuo en exteriores, haciendo que la serie sea ideal para seguimiento de activos a largo plazo y libre de mantenimiento. +[**SenseCAP T2000 Tracker**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html), un rastreador de activos LoRaWAN® de grado industrial, es compatible con posicionamiento GNSS, Bluetooth y Wi‑Fi para un seguimiento fiable en entornos interiores y exteriores. Cuenta con protección IP67, un acelerómetro triaxial integrado que detecta el estado de movimiento y un botón antimanipulación que activa una alarma de máxima prioridad si se retira el dispositivo. El T2000-A y el T2000-B admiten un funcionamiento prolongado con batería, mientras que el T2000-C con alimentación solar y batería recargable garantiza un uso continuo en exteriores, lo que hace que la serie sea ideal para el seguimiento de activos a largo plazo y sin mantenimiento. -

Catálogo para SenseCAP T2000 Tracker

+

Catálogo del Rastreador SenseCAP T2000

Introducción - Guía del Usuario + Inicio rápido + Formato de carga útil + Preguntas frecuentes
-### Integrado con Servidor de Red LoRaWAN® +### Integrado con el servidor de red LoRaWAN®
The Things Network @@ -34,9 +36,9 @@ url: https://wiki.seeedstudio.com/es/sensecap_t2000_tracker/ AWS IoT Core
-## Soporte Técnico y Discusión del Producto +## Soporte técnico y debate sobre el producto -¡Gracias por elegir nuestros productos! Estamos aquí para brindarle diferentes tipos de soporte para asegurar que su experiencia con nuestros productos sea lo más fluida posible. Ofrecemos varios canales de comunicación para satisfacer diferentes preferencias y necesidades. +Gracias por elegir nuestros productos. Estamos aquí para ofrecerte distintos tipos de soporte y garantizar que tu experiencia con nuestros productos sea lo más fluida posible. Ofrecemos varios canales de comunicación para adaptarnos a diferentes preferencias y necesidades.
diff --git a/sites/es/docs/Sensor/SenseCAP/es_SenseCAP_Decoder.md b/sites/es/docs/Sensor/SenseCAP/es_SenseCAP_Decoder.md index 4e5b7b7c4ab01..f3f5b5b5aa335 100644 --- a/sites/es/docs/Sensor/SenseCAP/es_SenseCAP_Decoder.md +++ b/sites/es/docs/Sensor/SenseCAP/es_SenseCAP_Decoder.md @@ -1,29 +1,29 @@ --- description: SenseCAP_Decoder -title: SenseCAP Decoder +title: Decodificador SenseCAP keywords: - SenseCAP_Decoder image: https://files.seeedstudio.com/wiki/wiki-platform/S-tempor.png slug: /SenseCAP_Decoder last_update: - date: 1/26/2026 + date: 3/12/2026 author: Janet createdAt: '2023-08-24' -updatedAt: '2026-03-03' +updatedAt: '2026-03-12' url: https://wiki.seeedstudio.com/es/SenseCAP_Decoder/ --- -El decodificador SenseCAP se utiliza para decodificar los mensajes LoRaWAN enviados desde los dispositivos SenseCAP LoRaWAN®. Después de la decodificación, las aplicaciones de los usuarios obtendrán mensajes más amigables y legibles. +El decodificador SenseCAP se utiliza para decodificar los mensajes LoRaWAN enviados desde los dispositivos LoRaWAN® SenseCAP. Después de la decodificación, las aplicaciones de los usuarios obtendrán mensajes más amigables y legibles. -### SenseCAP T1000 Tracker +### Rastreador SenseCAP T1000 -El [**SenseCAP T1000**](https://www.seeedstudio.com/sensecap-t1000-tracker?utm_source=emailsig&utm_medium=emailsig&utm_campaign=emailsig) es un rastreador LoRaWAN® compacto que utiliza GNSS/Wi-Fi/Bluetooth para un seguimiento preciso de ubicación en interiores y exteriores. Cuenta con capacidades de auto-geo-adaptación, almacenamiento local de datos y una impresionante duración de batería de meses. Además, está equipado con sensores de temperatura, luz y movimiento, lo que lo hace ideal para una variedad de aplicaciones basadas en ubicación. +[**SenseCAP T1000**](https://www.seeedstudio.com/sensecap-t1000-tracker?utm_source=emailsig&utm_medium=emailsig&utm_campaign=emailsig) es un rastreador LoRaWAN® compacto que utiliza GNSS/Wi-Fi/Bluetooth para un seguimiento de ubicación preciso tanto en interiores como en exteriores. Cuenta con capacidades de auto geo-adaptación, almacenamiento local de datos y una impresionante autonomía de batería de varios meses. Además, está equipado con sensores de temperatura, luz y movimiento, lo que lo hace ideal para una variedad de aplicaciones basadas en la ubicación.

pir

- Obtener Uno Ahora 🖱️ + Consigue uno ahora 🖱️
@@ -49,833 +49,6 @@ function decodeUplink (input) { decoded.messages.push({fport: fport, payload: bytesString}) return { data: decoded } } - if (fport !== 5) { - decoded.valid = false - return { data: decoded } - } - let measurement = messageAnalyzed(originMessage) - if (measurement.length === 0) { - decoded.valid = false - return { data: decoded } - } - - for (let message of measurement) { - if (message.length === 0) { - continue - } - let elements = [] - for (let element of message) { - if (element.errorCode) { - decoded.err = element.errorCode - decoded.errMessage = element.error - } else { - elements.push(element) - } - } - if (elements.length > 0) { - decoded.messages.push(elements) - } - } - // decoded.messages = measurement - return { data: decoded } -} - -function messageAnalyzed (messageValue) { - try { - let frames = unpack(messageValue) - let measurementResultArray = [] - for (let i = 0; i < frames.length; i++) { - let item = frames[i] - let dataId = item.dataId - let dataValue = item.dataValue - let measurementArray = deserialize(dataId, dataValue) - measurementResultArray.push(measurementArray) - } - return measurementResultArray - } catch (e) { - return e.toString() - } -} - -function unpack (messageValue) { - let frameArray = [] - - for (let i = 0; i < messageValue.length; i++) { - let remainMessage = messageValue - let dataId = remainMessage.substring(0, 2).toUpperCase() - let dataValue - let dataObj = {} - let packageLen - switch (dataId) { - case '01': - packageLen = 94 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '02': - packageLen = 32 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '03': - packageLen = 64 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '04': - packageLen = 20 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '05': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '06': - packageLen = 44 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '07': - packageLen = 84 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '08': - packageLen = 70 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '09': - packageLen = 36 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0A': - packageLen = 76 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0B': - packageLen = 62 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0C': - packageLen = 2 - if (remainMessage.length < packageLen) { - return frameArray - } - break - case '0D': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0E': - packageLen = getInt(remainMessage.substring(8, 10)) * 2 + 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, 8) + remainMessage.substring(10, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0F': - packageLen = 34 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '10': - packageLen = 26 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '11': - packageLen = 28 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - default: - return frameArray - } - if (dataValue.length < 2) { - break - } - frameArray.push(dataObj) - } - return frameArray -} - -function deserialize (dataId, dataValue) { - let measurementArray = [] - let eventList = [] - let measurement = {} - let collectTime = 0 - let groupId = 0 - let shardFlag = {} - let payload = '' - let result = [] - let dataArr = [] - switch (dataId) { - case '01': - measurementArray = getUpShortInfo(dataValue) - measurementArray.push(...getMotionSetting(dataValue.substring(30, 40))) - measurementArray.push(...getStaticSetting(dataValue.substring(40, 46))) - measurementArray.push(...getShockSetting(dataValue.substring(46, 52))) - measurementArray.push(...getTempSetting(dataValue.substring(52, 72))) - measurementArray.push(...getLightSetting(dataValue.substring(72, 92))) - break - case '02': - measurementArray = getUpShortInfo(dataValue) - break - case '03': - measurementArray.push(...getMotionSetting(dataValue.substring(0, 10))) - measurementArray.push(...getStaticSetting(dataValue.substring(10, 16))) - measurementArray.push(...getShockSetting(dataValue.substring(16, 22))) - measurementArray.push(...getTempSetting(dataValue.substring(22, 42))) - measurementArray.push(...getLightSetting(dataValue.substring(42, 62))) - break - case '04': - let interval = 0 - let workMode = getInt(dataValue.substring(0, 2)) - let heartbeatInterval = getMinsByMin(dataValue.substring(4, 8)) - let periodicInterval = getMinsByMin(dataValue.substring(8, 12)) - let eventInterval = getMinsByMin(dataValue.substring(12, 16)) - switch (workMode) { - case 0: - interval = heartbeatInterval - break - case 1: - interval = periodicInterval - break - case 2: - interval = eventInterval - break - } - measurementArray = [ - {measurementId: '3940', type: 'Work Mode', measurementValue: workMode}, - {measurementId: '3942', type: 'Heartbeat Interval', measurementValue: heartbeatInterval}, - {measurementId: '3943', type: 'Periodic Interval', measurementValue: periodicInterval}, - {measurementId: '3944', type: 'Event Interval', measurementValue: eventInterval}, - {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(16, 18))}, - {measurementId: '3900', type: 'Uplink Interval', measurementValue: interval} - ] - break; - case '05': - measurementArray = [ - {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(0, 2))}, - {measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(dataValue.substring(2, 4))}, - {measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(dataValue.substring(4, 6))}, - {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(6, 8))} - ] - break - case '06': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} - ] - break - case '07': - eventList = getEventStatus(dataValue.substring(0, 6)) - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} - ] - break - case '08': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} - ] - break - case '09': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} - ] - break - case '0A': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} - ] - break - case '0B': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, - ] - break - case '0D': - let errorCode = getInt(dataValue) - let error = '' - switch (errorCode) { - case 1: - error = 'FAILED TO OBTAIN THE UTC TIMESTAMP' - break - case 2: - error = 'ALMANAC TOO OLD' - break - case 3: - error = 'DOPPLER ERROR' - break - } - measurementArray.push({errorCode, error}) - break - case '0E': - shardFlag = getShardFlag(dataValue.substring(0, 2)) - groupId = getInt(dataValue.substring(2, 6)) - payload = dataValue.substring(6) - measurement = { - measurementId: '6152', - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'gnss-ng payload', - measurementValue: payload - } - measurementArray.push(measurement) - break - case '0F': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - shardFlag = getShardFlag(dataValue.substring(26, 28)) - groupId = getInt(dataValue.substring(28, 32)) - measurementArray.push({ - measurementId: '4200', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Event Status', - measurementValue: getEventStatus(dataValue.substring(0, 6)) - }) - measurementArray.push({ - measurementId: '4097', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) - }) - measurementArray.push({ - measurementId: '4199', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) - }) - measurementArray.push({ - measurementId: '3000', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) - }) - break - case '10': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - shardFlag = getShardFlag(dataValue.substring(18, 20)) - groupId = getInt(dataValue.substring(20, 24)) - measurementArray.push({ - measurementId: '4200', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Event Status', - measurementValue: getEventStatus(dataValue.substring(0, 6)) - }) - measurementArray.push({ - measurementId: '3000', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(16, 18)) - }) - break - case '11': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray.push({ - measurementId: '3576', - timestamp: collectTime, - type: 'Positing Status', - measurementValue: '' + getPositingStatus(dataValue.substring(0, 2)) - }) - measurementArray.push({ - timestamp: collectTime, - measurementId: '4200', - type: 'Event Status', - measurementValue: getEventStatus(dataValue.substring(2, 8)) - }) - if (!isNaN(parseFloat(getSensorValue(dataValue.substring(16, 20), 10)))) { - measurementArray.push({ - timestamp: collectTime, - measurementId: '4097', - type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) - }) - } - if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { - measurementArray.push({ - timestamp: collectTime, - measurementId: '4199', - type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) - }) - } - measurementArray.push({ - timestamp: collectTime, - measurementId: '3000', - type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) - }) - break - } - return measurementArray -} - -function getMotionId (str) { - return getInt(str) -} - -function getPositingStatus (str) { - return getInt(str) -} - -function getUpShortInfo (messageValue) { - return [ - { - measurementId: '3000', type: 'Battery', measurementValue: getBattery(messageValue.substring(0, 2)) - }, { - measurementId: '3502', type: 'Firmware Version', measurementValue: getSoftVersion(messageValue.substring(2, 6)) - }, { - measurementId: '3001', type: 'Hardware Version', measurementValue: getHardVersion(messageValue.substring(6, 10)) - }, { - measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(messageValue.substring(10, 12)) - }, { - measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(messageValue.substring(12, 14)) - }, { - measurementId: '3942', type: 'Heartbeat Interval', measurementValue: getMinsByMin(messageValue.substring(14, 18)) - }, { - measurementId: '3943', type: 'Periodic Interval', measurementValue: getMinsByMin(messageValue.substring(18, 22)) - }, { - measurementId: '3944', type: 'Event Interval', measurementValue: getMinsByMin(messageValue.substring(22, 26)) - }, { - measurementId: '3945', type: 'Sensor Enable', measurementValue: getInt(messageValue.substring(26, 28)) - }, { - measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(messageValue.substring(28, 30)) - } - ] -} - -function getMotionSetting (str) { - return [ - {measurementId: '3946', type: 'Motion Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3947', type: 'Any Motion Threshold', measurementValue: getSensorValue(str.substring(2, 6), 1)}, - {measurementId: '3948', type: 'Motion Start Interval', measurementValue: getMinsByMin(str.substring(6, 10))}, - ] -} - -function getStaticSetting (str) { - return [ - {measurementId: '3949', type: 'Static Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3950', type: 'Device Static Timeout', measurementValue: getMinsByMin(str.substring(2, 6))} - ] -} - -function getShockSetting (str) { - return [ - {measurementId: '3951', type: 'Shock Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3952', type: 'Shock Threshold', measurementValue: getInt(str.substring(2, 6))} - ] -} - -function getTempSetting (str) { - return [ - {measurementId: '3953', type: 'Temp Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3954', type: 'Event Temp Interval', measurementValue: getMinsByMin(str.substring(2, 6))}, - {measurementId: '3955', type: 'Event Temp Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))}, - {measurementId: '3956', type: 'Temp ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)}, - {measurementId: '3957', type: 'Temp ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)}, - {measurementId: '3958', type: 'Temp Warning Type', measurementValue: getInt(str.substring(18, 20))} - ] -} - -function getLightSetting (str) { - return [ - {measurementId: '3959', type: 'Light Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3960', type: 'Event Light Interval', measurementValue: getMinsByMin(str.substring(2, 6))}, - {measurementId: '3961', type: 'Event Light Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))}, - {measurementId: '3962', type: 'Light ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)}, - {measurementId: '3963', type: 'Light ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)}, - {measurementId: '3964', type: 'Light Warning Type', measurementValue: getInt(str.substring(18, 20))} - ] -} - -function getShardFlag (str) { - let bitStr = getByteArray(str) - return { - count: parseInt(bitStr.substring(0, 4), 2), - index: parseInt(bitStr.substring(4), 2) - } -} - -function getBattery (batteryStr) { - return loraWANV2DataFormat(batteryStr) -} -function getSoftVersion (softVersion) { - return `${loraWANV2DataFormat(softVersion.substring(0, 2))}.${loraWANV2DataFormat(softVersion.substring(2, 4))}` -} -function getHardVersion (hardVersion) { - return `${loraWANV2DataFormat(hardVersion.substring(0, 2))}.${loraWANV2DataFormat(hardVersion.substring(2, 4))}` -} - -function getSecondsByInt (str) { - return getInt(str) -} - -function getMinsByMin (str) { - return getInt(str) -} - -function getSensorValue (str, dig) { - if (str === '8000') { - return null - } else { - return loraWANV2DataFormat(str, dig) - } -} - -function bytes2HexString (arrBytes) { - var str = '' - for (var i = 0; i < arrBytes.length; i++) { - var tmp - var num = arrBytes[i] - if (num < 0) { - tmp = (255 + num + 1).toString(16) - } else { - tmp = num.toString(16) - } - if (tmp.length === 1) { - tmp = '0' + tmp - } - str += tmp - } - return str -} -function loraWANV2DataFormat (str, divisor = 1) { - let strReverse = bigEndianTransform(str) - let str2 = toBinary(strReverse) - if (str2.substring(0, 1) === '1') { - let arr = str2.split('') - let reverseArr = arr.map((item) => { - if (parseInt(item) === 1) { - return 0 - } else { - return 1 - } - }) - str2 = parseInt(reverseArr.join(''), 2) + 1 - return '-' + str2 / divisor - } - return parseInt(str2, 2) / divisor -} - -function bigEndianTransform (data) { - let dataArray = [] - for (let i = 0; i < data.length; i += 2) { - dataArray.push(data.substring(i, i + 2)) - } - return dataArray -} - -function toBinary (arr) { - let binaryData = arr.map((item) => { - let data = parseInt(item, 16) - .toString(2) - let dataLength = data.length - if (data.length !== 8) { - for (let i = 0; i < 8 - dataLength; i++) { - data = `0` + data - } - } - return data - }) - return binaryData.toString().replace(/,/g, '') -} - -function getSOSMode (str) { - return loraWANV2DataFormat(str) -} - -function getMacAndRssiObj (pair) { - let pairs = [] - if (pair.length % 14 === 0) { - for (let i = 0; i < pair.length; i += 14) { - let mac = getMacAddress(pair.substring(i, i + 12)) - if (mac) { - let rssi = getInt8RSSI(pair.substring(i + 12, i + 14)) - pairs.push({mac: mac, rssi: rssi}) - } else { - continue - } - } - } - return pairs -} - -function getMacAddress (str) { - if (str.toLowerCase() === 'ffffffffffff') { - return null - } - let macArr = [] - for (let i = 1; i < str.length; i++) { - if (i % 2 === 1) { - macArr.push(str.substring(i - 1, i + 1)) - } - } - let mac = '' - for (let i = 0; i < macArr.length; i++) { - mac = mac + macArr[i] - if (i < macArr.length - 1) { - mac = mac + ':' - } - } - return mac -} - -function getInt8RSSI (str) { - return loraWANV2DataFormat(str) -} - -function getInt (str) { - return parseInt(str, 16) -} - -function getEventStatus (str) { - // return getInt(str) - let bitStr = getByteArray(str) - let bitArr = [] - for (let i = 0; i < bitStr.length; i++) { - bitArr[i] = bitStr.substring(i, i + 1) - } - bitArr = bitArr.reverse() - let event = [] - for (let i = 0; i < bitArr.length; i++) { - if (bitArr[i] !== '1') { - continue - } - switch (i){ - case 0: - event.push({id:1, eventName:"Start moving event."}) - break - case 1: - event.push({id:2, eventName:"End movement event."}) - break - case 2: - event.push({id:3, eventName:"Motionless event."}) - break - case 3: - event.push({id:4, eventName:"Shock event."}) - break - case 4: - event.push({id:5, eventName:"Temperature event."}) - break - case 5: - event.push({id:6, eventName:"Light event."}) - break - case 6: - event.push({id:7, eventName:"SOS event."}) - break - case 7: - event.push({id:8, eventName:"Press once event."}) - break - } - } - return event -} - -function getByteArray (str) { - let bytes = [] - for (let i = 0; i < str.length; i += 2) { - bytes.push(str.substring(i, i + 2)) - } - return toBinary(bytes) -} - -function getWorkingMode (workingMode) { - return getInt(workingMode) -} - -function getPositioningStrategy (strategy) { - return getInt(strategy) -} - -function getUTCTimestamp(str){ - return parseInt(loraWANV2PositiveDataFormat(str)) * 1000 -} - -function loraWANV2PositiveDataFormat (str, divisor = 1) { - let strReverse = bigEndianTransform(str) - let str2 = toBinary(strReverse) - return parseInt(str2, 2) / divisor -} -``` - - - -
- -Para Helium - -```cpp -function Decoder (bytes, port) { - const bytesString = bytes2HexString(bytes) - const originMessage = bytesString.toLocaleUpperCase() - const fport = parseInt(port) - const decoded = { - valid: true, - err: 0, - payload: bytesString, - messages: [] - } - - if (fport === 199 || fport === 192) { - decoded.messages.push({fport: fport, payload: bytesString}) - return { data: decoded } - } - if (fport !== 5) { - decoded.valid = false - return { data: decoded } - } - let measurement = messageAnalyzed(originMessage) if (measurement.length === 0) { decoded.valid = false @@ -899,7 +72,6 @@ function Decoder (bytes, port) { decoded.messages.push(elements) } } - // decoded.messages = measurement return { data: decoded } } @@ -922,7 +94,6 @@ function messageAnalyzed (messageValue) { function unpack (messageValue) { let frameArray = [] - for (let i = 0; i < messageValue.length; i++) { let remainMessage = messageValue let dataId = remainMessage.substring(0, 2).toUpperCase() @@ -931,148 +102,93 @@ function unpack (messageValue) { let packageLen switch (dataId) { case '01': - packageLen = 94 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 94) + messageValue = remainMessage.substring(94) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '02': - packageLen = 32 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 32) + messageValue = remainMessage.substring(32) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '03': - packageLen = 64 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 64) + messageValue = remainMessage.substring(64) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '04': - packageLen = 20 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 20) + messageValue = remainMessage.substring(20) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '05': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 10) + messageValue = remainMessage.substring(10) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '06': - packageLen = 44 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 44) + messageValue = remainMessage.substring(44) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '07': - packageLen = 84 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 84) + messageValue = remainMessage.substring(84) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '08': - packageLen = 70 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 70) + messageValue = remainMessage.substring(70) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '09': - packageLen = 36 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 36) + messageValue = remainMessage.substring(36) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0A': - packageLen = 76 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 76) + messageValue = remainMessage.substring(76) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0B': - packageLen = 62 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 62) + messageValue = remainMessage.substring(62) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0C': - packageLen = 2 - if (remainMessage.length < packageLen) { - return frameArray - } break case '0D': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 10) + messageValue = remainMessage.substring(10) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0E': packageLen = getInt(remainMessage.substring(8, 10)) * 2 + 10 - if (remainMessage.length < packageLen) { - return frameArray - } dataValue = remainMessage.substring(2, 8) + remainMessage.substring(10, packageLen) messageValue = remainMessage.substring(packageLen) dataObj = { @@ -1080,34 +196,50 @@ function unpack (messageValue) { } break case '0F': - packageLen = 34 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 34) + messageValue = remainMessage.substring(34) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '10': - packageLen = 26 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 26) + messageValue = remainMessage.substring(26) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '11': - packageLen = 28 - if (remainMessage.length < packageLen) { - return frameArray + dataValue = remainMessage.substring(2, 28) + messageValue = remainMessage.substring(28) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + break + case '1A': + dataValue = remainMessage.substring(2, 56) + messageValue = remainMessage.substring(56) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue + } + break + case '1B': + dataValue = remainMessage.substring(2, 96) + messageValue = remainMessage.substring(96) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue + } + break + case '1C': + dataValue = remainMessage.substring(2, 82) + messageValue = remainMessage.substring(82) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue + } + break + case '1D': + dataValue = remainMessage.substring(2, 40) + messageValue = remainMessage.substring(40) dataObj = { 'dataId': dataId, 'dataValue': dataValue } @@ -1131,8 +263,7 @@ function deserialize (dataId, dataValue) { let groupId = 0 let shardFlag = {} let payload = '' - let result = [] - let dataArr = [] + let motionId = '' switch (dataId) { case '01': measurementArray = getUpShortInfo(dataValue) @@ -1188,59 +319,65 @@ function deserialize (dataId, dataValue) { break case '06': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '4197', timestamp: collectTime, motionId: motionId, type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, + {measurementId: '4198', timestamp: collectTime, motionId: motionId, type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, + {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} ] break case '07': eventList = getEventStatus(dataValue.substring(0, 6)) collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5001', timestamp: collectTime, motionId: motionId, type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, + {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} ] break case '08': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5002', timestamp: collectTime, motionId: motionId, type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, + {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} ] break case '09': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '4197', timestamp: collectTime, motionId: motionId, type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, + {measurementId: '4198', timestamp: collectTime, motionId: motionId, type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} ] break case '0A': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5001', timestamp: collectTime, motionId, type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} ] break case '0B': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5002', timestamp: collectTime, motionId, type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, ] break case '0D': @@ -1277,10 +414,11 @@ function deserialize (dataId, dataValue) { collectTime = getUTCTimestamp(dataValue.substring(8, 16)) shardFlag = getShardFlag(dataValue.substring(26, 28)) groupId = getInt(dataValue.substring(28, 32)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray.push({ measurementId: '4200', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, @@ -1290,42 +428,43 @@ function deserialize (dataId, dataValue) { measurementArray.push({ measurementId: '4097', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) + measurementValue: getSensorValue(dataValue.substring(16, 20), 10) }) measurementArray.push({ measurementId: '4199', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) + measurementValue: getSensorValue(dataValue.substring(20, 24)) }) measurementArray.push({ measurementId: '3000', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) + measurementValue: getBattery(dataValue.substring(24, 26)) }) break case '10': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) shardFlag = getShardFlag(dataValue.substring(18, 20)) groupId = getInt(dataValue.substring(20, 24)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray.push({ measurementId: '4200', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, @@ -1335,12 +474,12 @@ function deserialize (dataId, dataValue) { measurementArray.push({ measurementId: '3000', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(16, 18)) + measurementValue: getBattery(dataValue.substring(16, 18)) }) break case '11': @@ -1348,8 +487,8 @@ function deserialize (dataId, dataValue) { measurementArray.push({ measurementId: '3576', timestamp: collectTime, - type: 'Positing Status', - measurementValue: '' + getPositingStatus(dataValue.substring(0, 2)) + type: 'Positioning Status', + measurementValue: getPositingStatus(dataValue.substring(0, 2)) }) measurementArray.push({ timestamp: collectTime, @@ -1362,7 +501,7 @@ function deserialize (dataId, dataValue) { timestamp: collectTime, measurementId: '4097', type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) + measurementValue: getSensorValue(dataValue.substring(16, 20), 10) }) } if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { @@ -1370,14 +509,112 @@ function deserialize (dataId, dataValue) { timestamp: collectTime, measurementId: '4199', type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) + measurementValue: getSensorValue(dataValue.substring(20, 24)) }) } measurementArray.push({ timestamp: collectTime, measurementId: '3000', type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) + measurementValue: getBattery(dataValue.substring(24, 26)) + }) + break + case '1A': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) + measurementArray = [ + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '4197', timestamp: collectTime, motionId, type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, + {measurementId: '4198', timestamp: collectTime, motionId, type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, + {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, + {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(40, 44))}, + {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(44, 48))}, + {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(48, 52))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(52, 54))}, + ] + break + case '1B': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) + measurementArray = [ + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5001', timestamp: collectTime, motionId, type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, + {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, + {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(80, 84))}, + {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(84, 88))}, + {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(88, 92))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(92, 94))} + ] + break + case '1C': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) + measurementArray = [ + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5002', timestamp: collectTime, motionId, type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, + {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, + {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(66, 70))}, + {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(70, 74))}, + {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(74, 78))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(78, 80))} + ] + break + case '1D': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + measurementArray.push({ + measurementId: '3576', + timestamp: collectTime, + type: 'Positioning Status', + measurementValue: getPositingStatus(dataValue.substring(0, 2)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '4200', + type: 'Event Status', + measurementValue: getEventStatus(dataValue.substring(2, 8)) + }) + if (!isNaN(parseFloat(getSensorValue(dataValue.substring(16, 20), 10)))) { + measurementArray.push({ + timestamp: collectTime, + measurementId: '4097', + type: 'Air Temperature', + measurementValue: getSensorValue(dataValue.substring(16, 20), 10) + }) + } + if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { + measurementArray.push({ + timestamp: collectTime, + measurementId: '4199', + type: 'Light', + measurementValue: getSensorValue(dataValue.substring(20, 24)) + }) + } + measurementArray.push({ + timestamp: collectTime, + measurementId: '4210', + type: 'AccelerometerX', + measurementValue: getSensorValue(dataValue.substring(24, 28)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '4211', + type: 'AccelerometerY', + measurementValue: getSensorValue(dataValue.substring(28, 32)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '4212', + type: 'AccelerometerZ', + measurementValue: getSensorValue(dataValue.substring(32, 36)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '3000', + type: 'Battery', + measurementValue: getBattery(dataValue.substring(36, 38)) }) break } @@ -1389,6 +626,39 @@ function getMotionId (str) { } function getPositingStatus (str) { + let status = getInt(str) + switch (status) { + case 0: + return {id:status, statusName:"locate successful."} + case 1: + return {id:status, statusName:"The GNSS scan timed out."} + case 2: + return {id:status, statusName:"The Wi-Fi scan timed out."} + case 3: + return {id:status, statusName:"The Wi-Fi + GNSS scan timed out."} + case 4: + return {id:status, statusName:"The GNSS + Wi-Fi scan timed out."} + case 5: + return {id:status, statusName:"The Bluetooth scan timed out."} + case 6: + return {id:status, statusName:"The Bluetooth + Wi-Fi scan timed out."} + case 7: + return {id:status, statusName:"The Bluetooth + GNSS scan timed out."} + case 8: + return {id:status, statusName:"The Bluetooth + Wi-Fi + GNSS scan timed out."} + case 9: + return {id:status, statusName:"Location Server failed to parse the GNSS location."} + case 10: + return {id:status, statusName:"Location Server failed to parse the Wi-Fi location."} + case 11: + return {id:status, statusName:"Location Server failed to parse the Bluetooth location."} + case 12: + return {id:status, statusName:"Failed to parse location due to the poor accuracy."} + case 13: + return {id:status, statusName:"Time synchronization failed."} + case 14: + return {id:status, statusName:"Failed due to the old Almanac."} + } return getInt(str) } @@ -1526,7 +796,7 @@ function loraWANV2DataFormat (str, divisor = 1) { } }) str2 = parseInt(reverseArr.join(''), 2) + 1 - return '-' + str2 / divisor + return parseFloat('-' + str2 / divisor) } return parseInt(str2, 2) / divisor } @@ -1603,7 +873,6 @@ function getInt (str) { } function getEventStatus (str) { - // return getInt(str) let bitStr = getByteArray(str) let bitArr = [] for (let i = 0; i < bitStr.length; i++) { @@ -3334,17 +2603,17 @@ exports.handler = async (event) => {
-### SenseCAP T2000 Tracker +### Rastreador SenseCAP T2000 #### Decodificador -[**SenseCAP T2000 Tracker**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html), un rastreador de activos LoRaWAN® de grado industrial, soporta posicionamiento GNSS, Bluetooth y Wi-Fi para un seguimiento confiable en entornos interiores y exteriores. Cuenta con protección IP67, un acelerómetro de 3 ejes integrado que detecta el estado de movimiento, y un botón anti-manipulación que activa una alarma de máxima prioridad si el dispositivo es removido. El T2000-A y T2000-B soportan operación de batería de larga duración, mientras que el T2000-C alimentado por energía solar con batería recargable asegura uso continuo en exteriores, haciendo que la serie sea ideal para seguimiento de activos a largo plazo y libre de mantenimiento. +[**SenseCAP T2000 Tracker**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html), un rastreador de activos LoRaWAN® de grado industrial, es compatible con posicionamiento GNSS, Bluetooth y Wi‑Fi para un seguimiento fiable en entornos interiores y exteriores. Cuenta con protección IP67, un acelerómetro triaxial integrado que detecta el estado de movimiento y un botón antimanipulación que activa una alarma de máxima prioridad si se retira el dispositivo. El T2000-A y el T2000-B admiten un funcionamiento prolongado con batería, mientras que el T2000-C con energía solar y batería recargable garantiza un uso continuo en exteriores, lo que hace que la serie sea ideal para el seguimiento de activos a largo plazo y sin mantenimiento.

pir

- Obtener Uno Ahora + Consigue uno ahora

@@ -5527,17 +4796,17 @@ exports.handler = async (event) => { ``` -### Wio Tracker 1110 Dev Board +### Placa de desarrollo Wio Tracker 1110 -La [Wio Tracker 1110 Dev Board](https://www.seeedstudio.com/Wio-Tracker-1110-Dev-Board-p-5799.html) está basada en el [Módulo Inalámbrico Wio-WM1110](https://www.seeedstudio.com/Wio-WM1110-Module-LR1110-and-nRF52840-p-5676.html) e integra el transceptor LoRa® [LR1110 de Semtech](https://www.semtech.com/products/wireless-rf/lora-edge/lr1110) y un front-end de radio multipropósito para geolocalización, es una plataforma de desarrollo de seguimiento basada en LoRa fácil de usar. +La [Wio Tracker 1110 Dev Board](https://www.seeedstudio.com/Wio-Tracker-1110-Dev-Board-p-5799.html) está basada en el [módulo inalámbrico Wio-WM1110](https://www.seeedstudio.com/Wio-WM1110-Module-LR1110-and-nRF52840-p-5676.html) e integra el transceptor LoRa® [LR1110 de Semtech](https://www.semtech.com/products/wireless-rf/lora-edge/lr1110) y un front-end de radio multipropósito para geolocalización; es una plataforma de desarrollo de rastreo basada en LoRa, fácil de usar. -Con su tamaño compacto y interfaces ricas, la Wio Tracker 1110 Dev Board está convenientemente equipada con una antena integrada para fácil despliegue. Soporta el entorno de desarrollo Arduino y la pila de protocolos LoRaWAN, haciéndola ideal para proyectos IoT relacionados con seguimiento. +Con su tamaño compacto y sus interfaces ricas, la Wio Tracker 1110 Dev Board está convenientemente equipada con una antena integrada para un despliegue sencillo. Es compatible con el entorno de desarrollo de Arduino y la pila de protocolos LoRaWAN, lo que la hace ideal para proyectos de IoT relacionados con el rastreo.

pir

- Obtener Uno Ahora + Consigue uno ahora
@@ -7468,13 +6737,13 @@ function loraWANV2PositiveDataFormat(str) { ### Sensores LoRaWAN SenseCAP S210X -[SenseCAP S210X](https://www.seeedstudio.com/catalogsearch/result/?q=s210x) es una serie de sensores inalámbricos LoRaWAN®. Puede cubrir un rango de transmisión de 2km en escenas urbanas y 10km en escenas de línea de vista mientras mantiene un menor consumo de energía durante el proceso de transmisión. Junto con una batería reemplazable que soporta hasta 10 años de uso y una carcasa industrial IP66. Soporta temperatura de funcionamiento de -40 ~ 85℃ y puede ser desplegado en entornos hostiles. SenseCAP S210X es compatible con el protocolo LoRaWAN® V1.0.3 y puede trabajar con gateway LoRaWAN®. +[SenseCAP S210X](https://www.seeedstudio.com/catalogsearch/result/?q=s210x) es una serie de sensores inalámbricos LoRaWAN®. Puede cubrir un rango de transmisión de 2 km en escenarios urbanos y 10 km en escenarios de línea de vista, manteniendo un menor consumo de energía durante el proceso de transmisión. Junto con una batería reemplazable que admite hasta 10 años de uso y una carcasa industrial IP66. Admite una temperatura de funcionamiento de -40 ~ 85 ℃ y puede desplegarse en entornos hostiles. SenseCAP S210X es compatible con el protocolo LoRaWAN® V1.0.3 y puede funcionar con una puerta de enlace LoRaWAN®.

pir

- Obtener Uno Ahora 🖱️ + Consigue uno ahora 🖱️
@@ -9140,15 +8409,15 @@ exports.handler = async (event) => { -### SenseCAP S2100 Data Logger +### Registrador de Datos SenseCAP S2100 -El [SenseCAP S2100 Data Logger](https://www.seeedstudio.com/SenseCAP-S2100-LoRaWAN-Data-Logger-p-5361.html) es un dispositivo versátil que puede conectarse a sensores MODBUS-RTU RS485/Analógicos/GPIO, permitiendo la transmisión fácil de datos a la red LoRaWAN. Con su diseño LoRa e IP66, este dispositivo cuenta con una estabilidad y confiabilidad impresionantes, y puede cubrir un largo rango de transmisión mientras mantiene un consumo de energía ultra bajo. Es perfecto para uso exterior, y puede ser alimentado por batería o conectado a una fuente de alimentación externa de 12V para mayor flexibilidad. Cuando se conecta a la fuente de alimentación de 12V, la batería incorporada reemplazable actúa como fuente de energía de respaldo. Además, el S2100 Data Logger está optimizado para OTA con Bluetooth incorporado, haciendo que la configuración y actualizaciones sean rápidas y simples. Para completar, el convertidor S2110 permite al S2100 Data Logger conectarse a Sensores Grove, convirtiéndolo en una excelente opción para sensores LoRaWAN de nivel industrial DIY y despliegue a pequeña escala. +[SenseCAP S2100 Data Logger](https://www.seeedstudio.com/SenseCAP-S2100-LoRaWAN-Data-Logger-p-5361.html) es un dispositivo versátil que puede conectarse a sensores MODBUS-RTU RS485/Analógico/GPIO, lo que permite una transmisión sencilla de datos a la red LoRaWAN. Con su diseño LoRa e IP66, este dispositivo ofrece una estabilidad y fiabilidad impresionantes, y puede cubrir un largo alcance de transmisión manteniendo un consumo de energía ultra bajo. Es perfecto para uso en exteriores y puede alimentarse mediante batería o conectarse a una fuente de alimentación externa de 12 V para una flexibilidad aún mayor. Cuando está conectado a la fuente de alimentación de 12 V, la batería interna reemplazable actúa como fuente de alimentación de respaldo. Además, el Registrador de Datos S2100 está optimizado para OTA con Bluetooth integrado, lo que hace que la configuración y las actualizaciones sean rápidas y sencillas. Para rematar, el convertidor S2110 permite que el Registrador de Datos S2100 se conecte a sensores Grove, lo que lo convierte en una excelente opción para sensores LoRaWAN de nivel industrial DIY y despliegues a pequeña escala.
- Obtener Uno Ahora 🖱️ + Consigue uno ahora 🖱️
@@ -10403,15 +9672,15 @@ function bytes2HexString (arrBytes) { --- -### SenseCAP S2120 Sensor Meteorológico 8-en-1 +### SenseCAP S2120 Sensor meteorológico 8 en 1 -El [Sensor Meteorológico LoRaWAN SenseCAP S2120 8-en-1](https://www.seeedstudio.com/sensecap-s2120-lorawan-8-in-1-weather-sensor-p-5436.html) mide temperatura del aire, humedad, velocidad del viento, dirección del viento, precipitación, intensidad de luz, índice UV y presión barométrica. Permite un bajo costo de mantenimiento por su consumo ultra bajo de energía, rendimiento confiable, Bluetooth integrado y servicio de aplicación para configuración OTA y gestión remota de dispositivos. Soporta aplicaciones multi-escenario como patio trasero, jardines, agricultura inteligente, meteorología, ciudad inteligente, etc. +[SenseCAP S2120 8-in-1 LoRaWAN Weather Sensor](https://www.seeedstudio.com/sensecap-s2120-lorawan-8-in-1-weather-sensor-p-5436.html) mide la temperatura del aire, la humedad, la velocidad del viento, la dirección del viento, la lluvia, la intensidad de la luz, el índice UV y la presión barométrica. Permite un bajo coste de mantenimiento gracias a su consumo de energía ultrabajo, rendimiento fiable, Bluetooth integrado y servicio de aplicación para configuración OTA y gestión remota del dispositivo. Es compatible con aplicaciones en múltiples escenarios como patios traseros, jardines, agricultura inteligente, meteorología, ciudad inteligente, etc.

pir

- Obtener Uno Ahora 🖱️ + Consigue uno ahora 🖱️
@@ -10423,7 +9692,7 @@ import Tabs3 from '@theme/Tabs'; import TabItem3 from '@theme/TabItem'; - +
@@ -10886,7 +10155,7 @@ function bytes2HexString (arrBytes) {
- +
@@ -11508,15 +10777,15 @@ function Decoder (bytes, port) { --- -### SenseCAP A1101 - Sensor de IA de Visión LoRaWAN +### SenseCAP A1101 - LoRaWAN Vision AI Sensor -[SenseCAP A1101 - Sensor de IA de Visión LoRaWAN](https://www.seeedstudio.com/SenseCAP-A1101-LoRaWAN-Vision-AI-Sensor-p-5367.html) es un sensor de imagen inteligente habilitado con TinyML Edge AI. Soporta una variedad de modelos de IA como reconocimiento de imágenes, conteo de personas, detección de objetivos, reconocimiento de medidores, etc. También soporta el entrenamiento de modelos con TensorFlow Lite. +[SenseCAP A1101 - LoRaWAN Vision AI Sensor](https://www.seeedstudio.com/SenseCAP-A1101-LoRaWAN-Vision-AI-Sensor-p-5367.html) es un sensor de imagen inteligente TinyML Edge AI habilitado. Es compatible con una variedad de modelos de IA, como reconocimiento de imágenes, conteo de personas, detección de objetivos, reconocimiento de medidores, etc. También admite el entrenamiento de modelos con TensorFlow Lite.
@@ -11528,7 +10797,7 @@ import Tabs4 from '@theme/Tabs'; import TabItem4 from '@theme/TabItem'; - +
@@ -12568,36 +11837,36 @@ function toBinary (arr) { --- -### Cómo Usar +### Cómo usar ##### Preparación -Antes de configurar el decodificador, configure correctamente sus sensores y gateway según el manual del producto, y luego conéctese al servidor de red LoRaWAN que necesite. +Antes de configurar el decodificador, configura correctamente tus sensores y gateway de acuerdo con el manual del producto y luego conéctate al servidor de red LoRaWAN que necesites. -Tomamos The Things Stack como ejemplo, configure el decodificador según los siguientes pasos: +Tomamos The Things Stack como ejemplo, configura el decodificador según los siguientes pasos: -##### Configurar el Decodificador de Payload +##### Configurar el decodificador de carga útil -- Navegue a la pestaña `Payload Formats` de su dispositivo. -- Seleccione `Custom` para `Payload Format` -- Copie y pegue todo el contenido de `decoder.js` en el área de texto `decoder`. -- Haga clic en `save payload functions` +- Navega a la pestaña `Payload Formats` de tu dispositivo. +- Selecciona `Custom` para `Payload Format` +- Copia y pega todo el contenido de `decoder.js` en el área de texto `decoder`. +- Haz clic en `save payload functions`

pir

-##### Verificar los Mensajes Decodificados +##### Comprobar los mensajes decodificados -Puede probar el script de decodificación con un payload de muestra primero. +Puedes probar primero el script de decodificación con una carga útil de ejemplo. -Para hacer esto, copie un paquete de datos sin procesar como `01 01 10 98 53 00 00 01 02 10 A8 7A 00 00 AF 51` en la entrada de texto `Payload`, y seleccione el `FPort` según el manual del dispositivo, luego haga clic en el botón `Test`. Verá una estructura JSON analizada exitosamente a continuación. +Para ello, copia un paquete de datos en bruto como `01 01 10 98 53 00 00 01 02 10 A8 7A 00 00 AF 51` en la entrada de texto `Payload`, selecciona el `FPort` de acuerdo con el manual del dispositivo y luego haz clic en el botón `Test`. Verás una estructura JSON analizada correctamente debajo.

pir

-Ahora veamos la magia del script. Navegamos a la pestaña `Live Data`, y puede expandir cualquier mensaje cargado para verificar los `Event Fields` en el payload. Estos campos son poblados por el script. +Luego veamos la magia del script. Navegamos a la pestaña `Live Data`, y puedes expandir cualquier mensaje subido para comprobar los `Event Fields` en la carga útil. Estos campos son rellenados por el script.

pir

-Si está suscrito a los mensajes con la API de Datos MQTT de TTN, también obtendrá campos de payload JSON analizados. +Si estás suscribiendo los mensajes con el TTN's MQTT Data API, también obtendrás campos de carga útil JSON ya analizados. ```cpp Client mosq-TCSlhYcKaRCn3cIePE received PUBLISH (d0, q0, r0, m0, 'lorawan868/devices/2cf7f12010700041/up', ... (719 bytes)) @@ -12606,4 +11875,4 @@ lorawan868/devices/2cf7f12010700041/up {"app_id":"lorawan868","dev_id":"2cf7f120 ### Recurso -[Decodificador SenseCAP](https://github.com/Seeed-Solution/SenseCAP-Decoder) +[SenseCAP Decoder](https://github.com/Seeed-Solution/SenseCAP-Decoder) diff --git a/sites/es/sidebars.js b/sites/es/sidebars.js index e67ddfe846bee..502d193ab76a6 100644 --- a/sites/es/sidebars.js +++ b/sites/es/sidebars.js @@ -714,6 +714,8 @@ const sidebars = { label: 'Guía del usuario', items: [ 'Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/es_Quick_Start', + 'Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/es_Payload_Format', + 'Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/es_FAQ', ], }, { diff --git a/sites/es/static/js/language-switcher.js b/sites/es/static/js/language-switcher.js index 050a1e1f64544..9c8bd3c479a06 100644 --- a/sites/es/static/js/language-switcher.js +++ b/sites/es/static/js/language-switcher.js @@ -1,6 +1,6 @@ // 语言切换器 - 生产环境优化版本 -// 生成时间: 2026-03-11 13:45:57 (北京时间) -// 多语言页面: 2207 个 +// 生成时间: 2026-03-12 17:40:12 (北京时间) +// 多语言页面: 2209 个 (function() { 'use strict'; @@ -13186,6 +13186,16 @@ "es", "ja" ], + "/t2000_faq": [ + "cn", + "es", + "ja" + ], + "/t2000_payload_format": [ + "cn", + "es", + "ja" + ], "/": [ "en", "cn", diff --git a/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/ja_FAQ.md b/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/ja_FAQ.md new file mode 100644 index 0000000000000..15d0390916c7b --- /dev/null +++ b/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/ja_FAQ.md @@ -0,0 +1,136 @@ +--- +description: SenseCAP T2000 Tracker よくある質問 +title: よくある質問 +keywords: + - Tracker + - SenseCAP +image: https://files.seeedstudio.com/wiki/SenseCAP/SenseCAP_T2000_Tracker/SenseCAP_T2000_Tracker_QuickStart.webp +slug: /t2000_faq +last_update: + date: 3/12/2026 + author: Janet +createdAt: '2026-03-12' +updatedAt: '2026-03-12' +url: https://wiki.seeedstudio.com/ja/t2000_faq/ +--- + +# よくある質問 + +### 位置情報関連 + +
+T2000 の一般的な GNSS 測位精度はどのくらいですか? + +- 開けた空の下では、T2000 の GNSS 測位精度は一般的にメートルレベルの精度に達します。 +- テスト結果では CEP50(50%円形誤差半径)はおよそ **5~7 メートル** であり、これは位置ポイントの半数以上が真の位置からこの範囲内に収まることを意味します。 +- 実際の測位精度は、環境、衛星の見通し、設置条件などによって変動する場合があります。 + + +
+ + +
+なぜ GNSS 測位がドリフトして見えたり、GNSS の緯度・経度データが表示されないことがあるのですか? + +- GNSS の精度は、いくつかの環境要因の影響を受ける可能性があります: + - 建物、樹木、その他の障害物による衛星信号の遮断。 + - 壁や金属面での信号反射によって生じるマルチパス効果。 + - 近くの電子機器からの電磁干渉。 + - アンテナの向きや設置場所が不適切。 + +- 場合によっては、GNSS スキャンがタイムアウトしたために、デバイスが GNSS の緯度・経度データを報告しないことがあります。この状態はアップリンクペイロードで確認でき、上記と同じ環境条件により、**測位ステータス** フィールドに **"GNSS scan timeout"** と表示されます。 + +- 最良の結果を得るには、空がよく見える屋外の開けた場所にデバイスを設置してください。 + +
+ + +
+最良の GNSS 性能を得るために、T2000 はどのように設置すればよいですか? + +- 衛星信号の遮蔽物が最小限となる開けた環境にデバイスを設置してください。 +- GNSS アンテナ部分が空に向かって上向きになるようにしてください。 +- 大きな金属物体や高密度の構造物の近くへの設置は避けてください。 +- デバイスを覆ったり、密閉された金属ケースの中に入れたりしないでください。 +![Antenna](https://files.seeedstudio.com/wiki/SenseCAP/SenseCAP_T2000_Tracker/T2000-antenna.png) + +
+ +
+なぜ SenseCraft App の地図に Wi-Fi や Bluetooth の位置情報が表示されないのですか? + +- Wi-Fi および Bluetooth の位置情報には、ユーザーが呼び出して解析を行うサードパーティの地図解析サービスが必要です。現在、SenseCraft App がサポートしているのは GNSS 測位の表示のみです。 + +
+ +
+ +GNSS 測位の詳細については、次のブログを参照してください:[How Accurate is the SenseCAP T2000 GNSS Positioning?](https://www.seeedstudio.com/blog/2026/01/19/how-accurate-is-the-sensecap-t2000-gnss-positioning/) + + +### バッテリー関連 + +
+T2000-A/B と T2000-C のバッテリーの違いは何ですか? + +- **T2000-A/B** + - **8000mAh の一次電池**で駆動します。 + - 充電なしでの長期展開向けに設計されています。 + +- **T2000-C** + - **4000mAh の充電式バッテリー**で駆動します。 + - 屋外での連続動作を実現するために、**0.5W のソーラーパネル**を搭載しています。 + - 日照が得られ、メンテナンスを最小限に抑えたい設置環境に適しています。 + +
+ + +
+T2000-C のソーラー充電効率はどのくらいですか? + +- T2000-C は、長期の屋外運用をサポートするために、**0.5W のソーラーパネルと充電式バッテリー**を使用しています。 +- 良好な日照条件下では、ソーラーパネルは **最大約 60mA の充電電流**を生成し、1 時間あたりおよそ **60mAh** のエネルギーを供給できます(このデータは参考値です)。 + +
+ + +
+ソーラー充電効率に影響する要因は何ですか? + +- ソーラー充電性能は、次のような要因によって変動します: + - 日照時間と日射強度 + - パネルの向きと設置角度 + - 近くの物体による影 + - ソーラーパネル上のほこり、汚れ、ゴミ + - 周囲温度(バッテリー充電は 0~45°C の間で動作) + +- 最良の性能を得るには、直射日光が当たる場所にデバイスを設置し、定期的にパネル表面を確認してください。 + +
+ + +
+T2000-C はソーラー電源だけで連続動作できますか? + +- 低消費電力構成(アップリンク間隔を長くするなど)の場合、ソーラー充電によって日常運用中でもバッテリーレベルを維持、あるいは増加させることができます。 +- しかし、(1 分ごとのような)頻繁な送信間隔では、ソーラーパネルが補える量より多くの電力を消費する可能性があります。 +- ソーラー充電性能のより詳細な分析については、次のブログを参照してください:[How Efficient Is the Solar Charging on the SenseCAP T2000‑C?](https://www.seeedstudio.com/blog/2026/01/19/how-efficient-is-the-solar-charging-on-the-sensecap-t2000-c/) + +
+ +推定バッテリー寿命は、次の [Battery Life Calculator](https://files.seeedstudio.com/products/SenseCAP/T2000_Tracker/SenseCAP_Tracker_Battery_Life_Calculator_T2000.xls) を使用して算出できます。 + + +## 技術サポートと製品ディスカッション + +弊社製品をお選びいただきありがとうございます。弊社は、製品をできるだけスムーズにご利用いただけるよう、さまざまなサポートを提供しています。お好みやニーズに応じて選択いただける複数のコミュニケーションチャネルをご用意しています。 + +
+ + +
+ +
+ + +
\ No newline at end of file diff --git a/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/ja_Payload_Format.md b/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/ja_Payload_Format.md new file mode 100644 index 0000000000000..e6b620cd77f02 --- /dev/null +++ b/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/ja_Payload_Format.md @@ -0,0 +1,522 @@ +--- +description: SenseCAP T2000 Tracker ペイロードフォーマット +title: ペイロードフォーマット +keywords: + - トラッカー + - SenseCAP +image: https://files.seeedstudio.com/wiki/SenseCAP/SenseCAP_T2000_Tracker/SenseCAP_T2000_Tracker_QuickStart.webp +slug: /t2000_payload_format +last_update: + date: 3/12/2026 + author: Janet +createdAt: '2026-03-12' +updatedAt: '2026-03-12' +url: https://wiki.seeedstudio.com/ja/t2000_payload_format/ +--- + +# ペイロードフォーマット + +## アップリンクパケットの解析 + +トラッカーのデータプロトコルは、異なる情報に対応するために複数のパケットを提供しており、各パケットのバイト数は異なる場合があります。フレームの構造は下図のとおりです。フレーム内容は**ビッグエンディアンのバイト順**で送信されます。 + +|データ ID|データ値| +| - | :- | +|1 バイト|50 バイト(最大)| + +**データ ID**: 機能番号。
+**データ値**: 位置情報、センサーデータおよびその他の情報。 + +### 電源オンパケット (0x27) + +電源オンパケットは、デバイスの起動直後に送信されます。現在の設定パラメータとデバイスステータスが含まれます。フレーム ID は `0x27` で、全長は 46 バイトです。 + +| 0x27 | Byte2 | Byte3~4 | Byte5~6 | Byte7 | Byte8 | Byte9~10 | Byte11~12 | +| :--: | :---: | :-----: | :-----: | :--: | :--: | :------: | :-------: | +| ID | バッテリーレベル | ソフトウェアバージョン | ハードウェアバージョン | 動作モード | 測位ストラテジー | ハートビート間隔 | 周期モードアップリンク間隔 | + +| Byte13~14 | Byte15 | Byte16 | Byte17 | Byte18 | Byte19~20 | Byte21~22 | +| :-------: | :----: | :----: | :----: | :----: | :-------: | :-------: | +| イベントモードアップリンク間隔 | 3 軸加速度センサー有効化 | 分解アラーム有効化 | GNSS スキャンタイムアウト | 動作イベント有効化 | 3 軸動作しきい値 | 動作時アップリンク間隔 | + +| Byte23 | Byte24~25 | Byte26 | Byte27~28 | Byte29 | Byte30 | Byte31~46 | +| :----: | :-------: | :----: | :-------: | :----: | :----: | :-------: | +| 静止イベント有効化 | 静止タイムアウト | 衝撃イベント有効化 | 3 軸衝撃しきい値 | iBeacon スキャンタイムアウト (s) | UUID フィルター有効バイト数 | UUID フィルター (16 バイト) | + +**生ペイロード例** + +`27 56 0100 0101 01 08 02d0 003c 003c 00 01 3c 00 001e 0005 00 0168 00 012c 03 00 00000000000000000000000000000000` + +| Byte | 値 | 型 | 生データ | 説明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 27 | 27 はパケット ID です | +| 2 | バッテリーレベル | uint8 | 56 | `0x56` = 86(DEC)
バッテリーレベルは 86% です | +| 3~4 | ソフトウェアバージョン | uint16 | 0100 | `0x0100` = v1.0
ソフトウェアバージョンは v1.0 です | +| 5~6 | ハードウェアバージョン | uint16 | 0101 | `0x0101` = v1.1
ハードウェアバージョンは v1.1 です | +| 7 | 動作モード | uint8 | 01 | 01 = 周期モード
`00`: 待機モード
`01`: 周期モード
`02`: イベントモード | +| 8 | 測位ストラテジー | uint8 | 00 | 07 = 0x07、デバイスが Bluetooth + Wi-Fi + GNSS の測位ストラテジーを使用することを意味します
`00`: GNSS のみ
`01`: Wi-Fi のみ
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: Bluetooth のみ
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +| 9~10 | ハートビート間隔 | uint16 | 02d0 | `0x02D0` = 720 分 | +| 11~12 | 周期モードアップリンク間隔 | uint16 | 003c | `0x003C` = 60 分 | +| 13~14 | イベントモードアップリンク間隔 | uint16 | 003c | `0x003C` = 60 分 | +| 15 | 3 軸加速度センサー有効化 | uint8 | 00 | `00`: 無効
`01`: 有効 | +| 16 | 分解アラーム有効化 | uint8 | 01 | `00`: 無効
`01`: 有効 | +| 17 | GNSS スキャンタイムアウト | uint8 | 3c | `0x3C` = 60 秒 | +| 18 | 動作イベント有効化 | uint8 | 00 | `00`: 無効
`01`: 有効 | +| 19~20 | 3 軸動作しきい値 | uint16 | 001e | `0x001e` = 30 mg | +| 21~22 | 動作時アップリンク間隔 | uint16 | 0005 | `0x05` = 5 分 | +| 23 | 静止イベント有効化 | uint8 | 00 | `0x00`: 無効
`0x01`: 有効 | +| 24~25 | 静止タイムアウト | uint16 | 0168 | `0x0168` = 360 分 | +| 26 | 衝撃イベント有効化 | uint8 | 00 | `00`: 無効
`01`: 有効 | +| 27~28 | 3 軸衝撃しきい値 | uint16 | 012c | `0x012c` = 300 mg | +| 29 | iBeacon スキャンタイムアウト (s) | uint8 | 03 | `0x03` = 3 秒 | +| 30 | UUID フィルター有効バイト数 | uint8 | 00 | UUID フィルター内の有効バイト数 (0–16) | +| 31~46 | UUID フィルター | 16 bytes | 0000000000000000
0000000000000000 | 16 バイトの Bluetooth UUID フィルター。先頭 N バイト(byte30 で定義)が有効です | + +### 周期モードパケット (0x28) + +周期モードパラメータパケットには、現在の動作モード設定が含まれます。フレーム ID は `0x28` で、全長は 30 バイトです。 + +| 0x28 | Byte2 | Byte3 | Byte4~5 | Byte6~7 | Byte8~9 | Byte10 | Byte11 | Byte12 | Byte13 | Byte14 | Byte15~30 | +| :--: | :---: | :---: | :-----: | :-----: | :-----: | :----: | :----: | :----: | :----: | :----: | :-------: | +| ID | 動作モード | 測位ストラテジー | ハートビート間隔 | アップリンク間隔 | イベントモードアップリンク間隔 | 3 軸加速度センサー有効化 | 分解アラーム有効化 | GNSS スキャンタイムアウト | iBeacon スキャンタイムアウト | UUID フィルター有効バイト数 | UUID フィルター (16 バイト) | + +**生ペイロード例** + +`28 01 07 02d0 003c 003c 01 00 3c 0a 10 00000000000000000000000000000000` + +| Byte | 値 | 型 | 生データ | 説明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 28 | 28 はパケット ID です | +| 2 | 動作モード | uint8 | 01 | 01 = 周期モード
`00`: 待機モード
`01`: 周期モード
`02`: イベントモード | +| 3 | 測位ストラテジー | uint8 | 07 | 07 = 0x07、デバイスが Bluetooth + Wi-Fi + GNSS の測位ストラテジーを使用することを意味します
`00`: GNSS のみ
`01`: Wi-Fi のみ
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: Bluetooth のみ
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +| 4~5 | ハートビート間隔 | uint16 | 02d0 | `0x02D0` = 720 分 | +| 6~7 | アップリンク間隔 | uint16 | 003c | `0x003C` = 60 分 | +| 8~9 | イベントモードアップリンク間隔 | uint16 | 003c | `0x003C` = 60 分
イベントがトリガーされない場合、データは 60 分ごとにアップロードされます。
| +| 10 | 3 軸加速度センサー有効化 | uint8 | 01 | `00`: 無効
`01`: 有効 | +| 11 | 分解アラーム有効化 | uint8 | 00 | `00`: 無効
`01`: 有効 | +| 12 | GNSS スキャンタイムアウト | uint8 | 3c | `0x3C` = 60 秒 | +| 13 | iBeacon スキャンタイムアウト | uint8 | 0a | `0x0A` = 10 秒 | +| 14 | UUID フィルター有効バイト数 | uint8 | 10 | UUID フィルター内の有効バイト数 (0–16) | +| 15~30 | UUID フィルター | 16 bytes | 0000000000000000
0000000000000000 | 16 バイトの Bluetooth UUID フィルター。先頭 N バイト(byte14 で定義)が有効です | + +### イベントモードパケット (0x29) + +イベントパラメータパケットには、動作、静止、および衝撃イベントの設定が含まれます。フレーム ID は `0x29` で、全長は 12 バイトです。 + +| 0x29 | Byte2 | Byte3~4 | Byte5~6 | Byte7 | Byte8~9 | Byte10 | Byte11~12 | +| :--: | :---: | :-----: | :-----: | :--: | :-----: | :----: | :-------: | +| ID | 動作イベント有効化 | 3 軸動作しきい値 | 動作時アップリンク間隔 | 静止イベント有効化 | 静止タイムアウト | 衝撃イベント有効化 | 3 軸衝撃しきい値 | + +**生ペイロード例** + +`29 01 0064 001e 01 012c 00 012c` + +| Byte | 値 | 型 | 生データ | 説明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 29 | 29 はパケット ID です | +| 2 | 動作イベント有効化 | uint8 | 01 | `00`: 無効
`01`: 有効 | +| 3~4 | 3 軸動作しきい値 | uint16 | 0064 | `0x0064` = 100 mg | +| 5~6 | 動作時アップリンク間隔 | uint16 | 001e | `0x001E` = 30 分 | +| 7 | 静止イベント有効化 | uint8 | 01 | `0x00`: 無効
`0x01`: 有効 | +| 8~9 | 静止タイムアウト | uint16 | 012c | `0x012C` = 300 分 | +| 10 | 衝撃イベント有効化 | uint8 | 00 | `0x00`: 無効
`0x01`: 有効 | +| 11~12 | 3 軸衝撃しきい値 | uint16 | 0000 | `0x012c` = 300 mg | + +### ハートビートパケット (0x2A) + +ハートビートパケットは、デバイスが現在のステータスを報告するために定期的に送信されます。基本的なデバイス情報とセンサー状態が含まれます。フレーム ID は `0x2A` で、全長は 6 バイトです。 + +| 0x2A | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | +| :--: | :---: | :---: | :---: | :---: | :---: | +| ID | バッテリーレベル | 動作モード | 測位ストラテジー | 3 軸加速度センサー有効化 | 分解アラーム有効化 | + +**生ペイロード例** + +`2a 56 01 07 01 00` + +| Byte | 値 | 型 | 生データ | 説明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 2A | 2A はパケット ID です | +| 2 | バッテリーレベル | uint8 | 56 | `0x56` = 86(DEC)
バッテリーレベルは 86% です | +| 3 | 動作モード | uint8 | 01 | 01 = 周期モード
`00`: 待機モード
`01`: 周期モード
`02`: イベントモード | +| 4 | 測位ストラテジー | uint8 | 07 | 07 = 0x07、デバイスが Bluetooth + Wi-Fi + GNSS の測位ストラテジーを使用することを意味します
`00`: GNSS のみ
`01`: Wi-Fi のみ
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: Bluetooth のみ
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +| 5 | 3 軸加速度センサー有効化 | uint8 | 01 | `00`: 無効
`01`: 有効 | +| 6 | 分解アラーム有効化 | uint8 | 00 | `00`: 無効
`01`: 有効 | + +### GNSS 位置情報データパケット (加速度センサーオン, 0x2B) + +GPS 位置情報データパケットには、GNSS 測位データに加え、加速度センサーおよびバッテリー情報が含まれます。フレーム ID は `0x2B` で、全長は 23 バイトです。 + +| 0x2B | Byte2~3 | Byte4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15~18 | Byte19~22 | Byte23 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :-------: | :------: | :------: | :---: | +| ID | イベントステータス | モーション ID | UTC タイムスタンプ | 加速度 X | 加速度 Y | 加速度 Z | 経度 | 緯度 | バッテリーレベル | + +**生ペイロード例** + +`2b 0100 00 694b3dc6 032f fffe 0241 06ca5098 01587ee4 62` + +| Byte | 値 | 型 | 生データ | 説明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 2B | 2B はパケット ID です | +| 2~3 | イベントステータス | uint16 | 0100 | `0x0100` = 分解イベント
Bit 0: false
Bit 1: 動作開始イベント
Bit 2: 動作終了イベント
Bit 3: 静止イベント
Bit 4: 衝撃イベント
Bit 5: 温度イベント
Bit 6: 光イベント
Bit 7: SOS イベント
Bit 8: 1 回押下イベント
Bit 9: 分解イベント

16 進数への変換:
`0x0001`: 動作開始イベント
`0x0002`: 動作終了イベント
`0x0004`: 静止イベント
`0x0008`: 衝撃イベント
`0x0010`: 温度イベント
`0x0020`: 光イベント
`0x0040`: SOS イベント
`0x0080`: 1 回押下イベント
`0x0100`: 分解イベント | +| 4 | モーション ID | uint8 | 00 | `0`: 特定の動作として記録する必要はありません。
`1~255`: 同一の動作状態下で報告された測位データ(同じ ID は同じ動作を指します) | +| 5~8 | UTC タイムスタンプ | uint32 | 694b3dc6 | `0x694B3DC6` = 1766538694(DEC) 秒

UTC 時刻に変換:
2025-12-24 01:11:34 | +| 9~10 | 加速度 X | int16 | 032f | `0x032F` = 815 mg | +| 11~12 | 加速度 Y | int16 | fffe | `0xFFFE` = -2 mg | +| 13~14 | 加速度 Z | int16 | 0241 | `0x0241` = 577 mg | +| 15~18 | 経度 | uint32 | 06ca5098 | `0x06CA5098` = 113,922,200 → 113.922200° | +| 19~22 | 緯度 | uint32 | 01587ee4 | `0x01587EE4` = 22,576,868 → 22.576868° | +| 23 | バッテリーレベル | uint8 | 62 | `0x62` = 98% | + +### Wi-Fi 位置情報データパケット(加速度センサーオン, 0x2C) + +Wi-Fi 位置情報パケットには、Wi-Fi スキャン結果に加えて加速度センサーおよびバッテリー情報が含まれます。フレーム ID は `0x2C` で、全長はスキャンされた Wi-Fi アクセスポイントの数に応じて動的に変化します(23 + (n-1) * 7 バイト、ここで n は MAC-RSSI ペアの数です)。 + +| 0x2C | Byte2~3 | Byte4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15 | Byte16 | Byte17+(n-1)*7 ~ Byte23+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :-------: | :---: | :---: | :---------------------------: | +| ID | イベントステータス | モーション ID | UTC タイムスタンプ | 加速度センサー X | 加速度センサー Y | 加速度センサー Z | バッテリーレベル | MAC-RSSI カウント (n) | MAC-RSSI ペア (n) | + +**MAC-RSSI フォーマット** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| MAC アドレス (6 bytes) | RSSI (int8) | + +**生ペイロード例** + +`2c 0000 00 69685f82 0004 0015 03e5 64 05 107c61841bf8 e4 3447d468f627 e1 a4ba70bc229d d3 9483c46d5dfc d2 4c10d567b467 d0` + +| Byte | 値 | 型 | 生データ | 説明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 2C | 2C はパケット ID です | +| 2~3 | イベントステータス | uint16 | 0000 |`0x0000` = イベント未発生
Bit 0: false
Bit 1: 移動開始イベント
Bit 2: 移動終了イベント
Bit 3: 静止イベント
Bit 4: 衝撃イベント
Bit 5: 温度イベント
Bit 6: 光イベント
Bit 7: SOS イベント
Bit 8: 1 回押下イベント
Bit 9: 分解イベント

16 進数への変換:
`0x0001`: 移動開始イベント
`0x0002`: 移動終了イベント
`0x0004`: 静止イベント
`0x0008`: 衝撃イベント
`0x0010`: 温度イベント
`0x0020`: 光イベント
`0x0040`: SOS イベント
`0x0080`: 1 回押下イベント
`0x0100`: 分解イベント| +| 4 | モーション ID | uint8 | 00 | `0`: 特定のモーションとして記録する必要はありません。
`1~255`: 同一モーション状態下で報告される測位データ(同じ ID は同じモーションを指します) | +| 5~8 | UTC タイムスタンプ | uint32 | 69685f82 | `0x69685F82` = 1768447874(DEC) 秒

UTC 時刻に変換:
2026-01-15 03:31:14 | +| 9~10 | 加速度センサー X | int16 | 0004 | `0x0004` = 4 mg | +| 11~12 | 加速度センサー Y | int16 | 0015 | `0x0015` = 21 mg | +| 13~14 | 加速度センサー Z | int16 | 03e5 | `0x03E5` = 997 mg | +| 15 | バッテリーレベル | uint8 | 64 | `0x64` = 100% | +| 16 | MAC-RSSI カウント (n) | uint8 | 05 | 検出された Wi-Fi アクセスポイントの数(n = 5) | +| 17~23 | MAC-RSSI ペア 1 | 7 bytes | 107c61841bf8 e4 | MAC: `10:7C:61:84:1B:F8`, RSSI: `0xE4` = -28 (int8) | +| 24~30 | MAC-RSSI ペア 2 | 7 bytes | 3447d468f627 e1 | MAC: `34:47:D4:68:F6:27`, RSSI: `0xE1` = -31 (int8) | +| 31~37 | MAC-RSSI ペア 3 | 7 bytes | a4ba70bc229d d3 | MAC: `A4:BA:70:BC:22:9D`, RSSI: `0xD3` = -45 (int8) | +| 38~44 | MAC-RSSI ペア 4 | 7 bytes | 9483c46d5dfc d2 | MAC: `94:83:C4:6D:5D:FC`, RSSI: `0xD2` = -46 (int8) | +| 45~51 | MAC-RSSI ペア 5 | 7 bytes | 4c10d567b467 d0 | MAC: `4C:10:D5:67:B4:67`, RSSI: `0xD0` = -48 (int8) | + +### BLE 位置情報データパケット(加速度センサーオン,0x2D) + +BLE 位置情報パケットには、Bluetooth スキャン結果に加えて加速度センサーおよびバッテリー情報が含まれます。フレーム ID は `0x2D` で、全長はスキャンされた Bluetooth デバイスの数に応じて動的に変化します(23 + (n-1) * 7 バイト、ここで n は MAC-RSSI ペアの数で、最大 n = 5)。 + +| 0x2D | Byte2~3 | Byte4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15 | Byte16 | Byte17+(n-1)*7 ~ Byte23+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :-------: | :---: | :---: | :---------------------------: | +| ID | イベントステータス | モーション ID | UTC タイムスタンプ | 加速度センサー X | 加速度センサー Y | 加速度センサー Z | バッテリーレベル | MAC-RSSI カウント (n) | MAC-RSSI ペア (n) | + +**MAC-RSSI フォーマット** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| MAC アドレス (6 bytes) | RSSI (int8) | + +**生ペイロード例** + +`2d 0000 00 69686032 fff9 0015 03df 64 05 c30000564b3b ce c20303003f00 ce 588c81a0fbf2 cc c20303003f03 cb c30000564af2 c7` + +| Byte | 値 | 型 | 生データ | 説明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 2D | 2D はパケット ID です | +| 2~3 | イベントステータス | uint16 | 0000 |`0x0000` = イベント未発生
Bit 0: false
Bit 1: 移動開始イベント
Bit 2: 移動終了イベント
Bit 3: 静止イベント
Bit 4: 衝撃イベント
Bit 5: 温度イベント
Bit 6: 光イベント
Bit 7: SOS イベント
Bit 8: 1 回押下イベント
Bit 9: 分解イベント

16 進数への変換:
`0x0001`: 移動開始イベント
`0x0002`: 移動終了イベント
`0x0004`: 静止イベント
`0x0008`: 衝撃イベント
`0x0010`: 温度イベント
`0x0020`: 光イベント
`0x0040`: SOS イベント
`0x0080`: 1 回押下イベント
`0x0100`: 分解イベント| +| 4 | モーション ID | uint8 | 00 | `0`: 特定のモーションとして記録する必要はありません。
`1~255`: 同一モーション状態下で報告される測位データ(同じ ID は同じモーションを指します) | +| 5~8 | UTC タイムスタンプ | uint32 | 69686032 | `0x69686032` = 1768448050(DEC) 秒

UTC 時刻に変換:
2026-01-15 03:34:10 | +| 9~10 | 加速度センサー X | int16 | fff9 | `0xFFF9` = -7 mg | +| 11~12 | 加速度センサー Y | int16 | 0015 | `0x0015` = 21 mg | +| 13~14 | 加速度センサー Z | int16 | 03df | `0x03DF` = 991 mg | +| 15 | バッテリーレベル | uint8 | 64 | `0x64` = 100% | +| 16 | MAC-RSSI カウント (n) | uint8 | 05 | 検出された Bluetooth デバイスの数(n = 5、最大 5) | +| 17~23 | MAC-RSSI ペア 1 | 7 bytes | c30000564b3b ce | MAC: `C3:00:00:56:4B:3B`, RSSI: `0xCE` = -50 (int8) | +| 24~30 | MAC-RSSI ペア 2 | 7 bytes | c20303003f00 ce | MAC: `C2:03:03:00:3F:00`, RSSI: `0xCE` = -50 (int8) | +| 31~37 | MAC-RSSI ペア 3 | 7 bytes | 588c81a0fbf2 cc | MAC: `58:8C:81:A0:FB:F2`, RSSI: `0xCC` = -52 (int8) | +| 38~44 | MAC-RSSI ペア 4 | 7 bytes | c20303003f03 cb | MAC: `C2:03:03:00:3F:03`, RSSI: `0xCB` = -53 (int8) | +| 45~51 | MAC-RSSI ペア 5 | 7 bytes | c30000564af2 c7 | MAC: `C3:00:00:56:4A:F2`, RSSI: `0xC7` = -57 (int8) | + +### GNSS 位置情報データパケット(加速度センサーオフ, 0x2E) + +GNSS 位置情報データパケットには、GPS 測位データに加えてバッテリー情報が含まれます。フレーム ID は `0x2E` で、全長は 17 バイトです。 + +| 0x2E | Byte2~3 | Byte4 | Byte5~8 | Byte9~12 | Byte13~16 | Byte17 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :----: | +| ID | イベントステータス | モーション ID | UTC タイムスタンプ | 経度 | 緯度 | バッテリーレベル | + +**生ペイロード例** + +`2e 0100 01 64f1a2b3 06ca5098 01587ee4 62` + +| Byte | 値 | 型 | 生データ | 説明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 2E | 2E はパケット ID です | +| 2~3 | イベントステータス | uint16 | 0000 |`0x0000` = イベント未発生
Bit 0: false
Bit 1: 移動開始イベント
Bit 2: 移動終了イベント
Bit 3: 静止イベント
Bit 4: 衝撃イベント
Bit 5: 温度イベント
Bit 6: 光イベント
Bit 7: SOS イベント
Bit 8: 1 回押下イベント
Bit 9: 分解イベント

16 進数への変換:
`0x0001`: 移動開始イベント
`0x0002`: 移動終了イベント
`0x0004`: 静止イベント
`0x0008`: 衝撃イベント
`0x0010`: 温度イベント
`0x0020`: 光イベント
`0x0040`: SOS イベント
`0x0080`: 1 回押下イベント
`0x0100`: 分解イベント| +| 4 | モーション ID | uint8 | 00 | `0`: 特定のモーションとして記録する必要はありません。
`1~255`: 同一モーション状態下で報告される測位データ(同じ ID は同じモーションを指します) | +| 5~8 | UTC タイムスタンプ | uint32 | 64f1a2b3 | `0x64f1a2b3` = 1693557427(DEC) 秒

UTC 時刻に変換:
2023-09-01 08:37:07 | +| 9~12 | 経度 | uint32 | 06ca5098 | `0x06CA5098` = 113,922,200 → 113.922200° | +| 13~16 | 緯度 | uint32 | 01587ee4 | `0x01587EE4` = 22,576,868 → 22.576868° | +| 17 | バッテリーレベル | uint8 | 62 | `0x62` = 98% | + +### Wi-Fi 位置情報データパケット(加速度センサーオフ, 0x2F) + +Wi-Fi 位置情報データパケットには、Wi-Fi スキャン結果に加えてバッテリー情報が含まれます。フレーム ID は `0x2F` で、全長はスキャンされた Wi-Fi アクセスポイントの数に応じて動的に変化します(17 + (n-1) * 7 バイト、ここで n は MAC-RSSI ペアの数で、最大 n = 5)。 + +| 0x2F | Byte2~3 | Byte4 | Byte5~8 | Byte9 | Byte10 | Byte11+(n-1)*7 ~ Byte16+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :---: | :----: | :---------------------------: | +| ID | イベントステータス | モーション ID | UTC タイムスタンプ | バッテリーレベル | MAC-RSSI カウント (n) | MAC-RSSI ペア (n) | + +**MAC-RSSI フォーマット** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| MAC アドレス (6 bytes) | RSSI (int8) | + +**生ペイロード例** + +`2f 0000 00 69685f82 64 05 107c61841bf8 e4 3447d468f627 e1 a4ba70bc229d d3 9483c46d5dfc d2 4c10d567b467 d0` + +| Byte | 値 | 型 | 生データ | 説明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 2F | 2F はパケット ID です | +| 2~3 | イベントステータス | uint16 | 0000 |`0x0000` = イベント未発生
Bit 0: false
Bit 1: 移動開始イベント
Bit 2: 移動終了イベント
Bit 3: 静止イベント
Bit 4: 衝撃イベント
Bit 5: 温度イベント
Bit 6: 光イベント
Bit 7: SOS イベント
Bit 8: 1 回押下イベント
Bit 9: 分解イベント

16 進数への変換:
`0x0001`: 移動開始イベント
`0x0002`: 移動終了イベント
`0x0004`: 静止イベント
`0x0008`: 衝撃イベント
`0x0010`: 温度イベント
`0x0020`: 光イベント
`0x0040`: SOS イベント
`0x0080`: 1 回押下イベント
`0x0100`: 分解イベント| +| 4 | モーション ID | uint8 | 00 | `0`: 特定のモーションとして記録する必要はありません。
`1~255`: 同一モーション状態下で報告される測位データ(同じ ID は同じモーションを指します) | +| 5~8 | UTC タイムスタンプ | uint32 | 69685f82 | `0x69685F82` = 1768447874(DEC) 秒

UTC 時刻に変換:
2026-01-15 03:31:14 | +| 9 | バッテリーレベル | uint8 | 64 | `0x64` = 100% | +| 10 | MAC-RSSI カウント (n) | uint8 | 05 | 検出された Wi-Fi アクセスポイントの数(n = 5、最大 5) | +| 11~17 | MAC-RSSI ペア 1 | 7 bytes | 107c61841bf8 e4 | MAC: `10:7C:61:84:1B:F8`,
RSSI: `0xE4` = -28 (int8) | +| 18~24 | MAC-RSSI ペア 2 | 7 bytes | 3447d468f627 e1 | MAC: `34:47:D4:68:F6:27`,
RSSI: `0xE1` = -31 (int8) | +| 25~31 | MAC-RSSI ペア 3 | 7 bytes | a4ba70bc229d d3 | MAC: `A4:BA:70:BC:22:9D`,
RSSI: `0xD3` = -45 (int8) | +| 32~38 | MAC-RSSI ペア 4 | 7 bytes | 9483c46d5dfc d2 | MAC: `94:83:C4:6D:5D:FC`,
RSSI: `0xD2` = -46 (int8) | +| 39~45 | MAC-RSSI ペア 5 | 7 bytes | 4c10d567b467 d0 | MAC: `4C:10:D5:67:B4:67`,
RSSI: `0xD0` = -48 (int8) | + +### BLE 位置情報データパケット(加速度センサー Off, 0x30) + +BLE 位置情報データパケットには、Bluetooth スキャン結果とバッテリー情報が含まれます。フレーム ID は `0x30` で、全長はスキャンされた Bluetooth デバイス数に応じて動的に変化します(17 + (n-1) * 7 バイト、n は MAC-RSSI ペアの数で、最大 n = 5)。 + +| 0x30 | Byte2~3 | Byte4 | Byte5~8 | Byte9 | Byte10 | Byte11+(n-1)*7 ~ Byte16+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :---: | :----: | :---------------------------: | +| ID | イベントステータス | モーション ID | UTC タイムスタンプ | バッテリーレベル | MAC-RSSI カウント (n) | MAC-RSSI ペア (n) | + +**MAC-RSSI フォーマット** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| MAC アドレス (6 bytes) | RSSI (int8) | + +**生ペイロード例** + +`30 0000 00 69686032 64 05 c30000564b3b ce c20303003f00 ce 588c81a0fbf2 cc c20303003f03 cb c30000564af2 c7` + +| Byte | Value | Type | Raw Data | Description | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 30 | 30 はパケット ID です | +| 2~3 | イベントステータス | uint16 | 0000 |`0x0000` = イベント未発生
Bit 0: false
Bit 1: 移動開始イベント
Bit 2: 移動終了イベント
Bit 3: 静止イベント
Bit 4: 衝撃イベント
Bit 5: 温度イベント
Bit 6: 光イベント
Bit 7: SOS イベント
Bit 8: 1 回押下イベント
Bit 9: 分解イベント

16 進数への変換:
`0x0001`: 移動開始イベント
`0x0002`: 移動終了イベント
`0x0004`: 静止イベント
`0x0008`: 衝撃イベント
`0x0010`: 温度イベント
`0x0020`: 光イベント
`0x0040`: SOS イベント
`0x0080`: 1 回押下イベント
`0x0100`: 分解イベント| +| 4 | モーション ID | uint8 | 00 | `0`: 特定のモーションとして記録する必要はありません。
`1~255`: 同一モーション状態で報告された位置情報データ(同じ ID は同じモーションを示す) | +| 5~8 | UTC タイムスタンプ | uint32 | 69686032 | `0x69686032` = 1768448050(DEC) 秒

UTC 時刻に変換:
2026-01-15 03:34:10 | +| 9 | バッテリーレベル | uint8 | 64 | `0x64` = 100% | +| 10 | MAC-RSSI カウント (n) | uint8 | 05 | 検出された Bluetooth デバイス数(n = 5、最大 5) | +| 11~17 | MAC-RSSI ペア 1 | 7 bytes | c30000564b3b ce | MAC: `C3:00:00:56:4B:3B`,
RSSI: `0xCE` = -50 (int8) | +| 18~24 | MAC-RSSI ペア 2 | 7 bytes | c20303003f00 ce | MAC: `C2:03:03:00:3F:00`,
RSSI: `0xCE` = -50 (int8) | +| 25~31 | MAC-RSSI ペア 3 | 7 bytes | 588c81a0fbf2 cc | MAC: `58:8C:81:A0:FB:F2`,
RSSI: `0xCC` = -52 (int8) | +| 32~38 | MAC-RSSI ペア 4 | 7 bytes | c20303003f03 cb | MAC: `C2:03:03:00:3F:03`,
RSSI: `0xCB` = -53 (int8) | +| 39~45 | MAC-RSSI ペア 5 | 7 bytes | c30000564af2 c7 | MAC: `C3:00:00:56:4A:F2`,
RSSI: `0xC7` = -57 (int8) | + +### 加速度センサー付き位置情報ステータスパケット (0x31) + +位置情報ステータスパケットには、位置情報ステータスに加えて、加速度センサーデータ、イベントステータス、およびバッテリー情報が含まれます。フレーム ID は `0x31` で、全長は 15 バイトです。 + +| 0x31 | Byte2 | Byte3~4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15 | +| :--: | :---: | :-----: | :-----: | :------: | :-------: | :-------: | :---: | +| ID | 位置情報ステータス | イベントステータス | UTC タイムスタンプ | 加速度センサー X | 加速度センサー Y | 加速度センサー Z | バッテリーレベル | + +**生ペイロード例** + +`31 00 0100 694b3db0 003a 039d fe84 62` + +| Byte | Value | Type | Raw Data | Description | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 31 | 31 はパケット ID です | +| 2 | 位置情報ステータス | uint8 | 00 |`0x00`: 位置特定成功。
`0x01`: GNSS スキャンがタイムアウトしました。
`0x02`: Wi-Fi スキャンがタイムアウトしました。
`0x03`: Wi-Fi + GNSS スキャンがタイムアウトしました。
`0x04`: GNSS + Wi-Fi スキャンがタイムアウトしました。
`0x05`: Bluetooth スキャンがタイムアウトしました。
`0x06`: Bluetooth + Wi-Fi スキャンがタイムアウトしました。
`0x07`: Bluetooth + GNSS スキャンがタイムアウトしました。
`0x08`: Bluetooth + Wi-Fi + GNSS スキャンがタイムアウトしました。
`0x09`: Location Server が GNSS 位置情報の解析に失敗しました。
`0x0A`: Location Server が Wi-Fi 位置情報の解析に失敗しました。
`0x0B`: Location Server が Bluetooth 位置情報の解析に失敗しました。
`0x0C`: 精度が低いため位置情報の解析に失敗しました。
`0x0D`: 時刻同期に失敗しました。
`0x0E`: 古い Almanac が原因で失敗しました。
`0x0F`: GNSS + Bluetooth スキャンがタイムアウトしました。 | +| 3~4 | イベントステータス | uint16 | 0000 |`0x0000` = イベント未発生
Bit 0: false
Bit 1: 移動開始イベント
Bit 2: 移動終了イベント
Bit 3: 静止イベント
Bit 4: 衝撃イベント
Bit 5: 温度イベント
Bit 6: 光イベント
Bit 7: SOS イベント
Bit 8: 1 回押下イベント
Bit 9: 分解イベント

16 進数への変換:
`0x0001`: 移動開始イベント
`0x0002`: 移動終了イベント
`0x0004`: 静止イベント
`0x0008`: 衝撃イベント
`0x0010`: 温度イベント
`0x0020`: 光イベント
`0x0040`: SOS イベント
`0x0080`: 1 回押下イベント
`0x0100`: 分解イベント | +| 5~8 | UTC タイムスタンプ | uint32 | 694B3DB0 | `0x694B3DB0` = 1766538672(DEC) 秒

UTC 時刻に変換:
2025-12-24 01:11:12 | +| 9~10 | 加速度センサー X | int16 | 003a | `0x003A` = 58 mg | +| 11~12 | 加速度センサー Y | int16 | 039d | `0x039D` = 925 mg | +| 13~14 | 加速度センサー Z | int16 | fe84 | `0xFE84` = -380 mg | +| 15 | バッテリーレベル | uint8 | 62 | `0x62` = 98% | + +### 位置情報ステータスパケット(加速度センサー Off, 0x32) + +位置情報ステータスパケットには、位置情報ステータスに加えて、イベントステータスとバッテリー情報が含まれます。フレーム ID は `0x32` で、全長は 9 バイトです。 + +| 0x32 | Byte2 | Byte3~4 | Byte5~8 | Byte9 | +| :--: | :---: | :-----: | :-----: | :---: | +| ID | 位置情報ステータス | イベントステータス | UTC タイムスタンプ | バッテリーレベル | + +**生ペイロード例** + +`32 00 0100 694b3db0 62` + +| Byte | Value | Type | Raw Data | Description | +| :---: | :--- | :---: | :---: | :--- | +| 1 | フレーム ID | uint8 | 32 | 32 はパケット ID です | +| 2 | 位置情報ステータス | uint8 | 00 |`0x00`: 位置特定成功。
`0x01`: GNSS スキャンがタイムアウトしました。
`0x02`: Wi-Fi スキャンがタイムアウトしました。
`0x03`: Wi-Fi + GNSS スキャンがタイムアウトしました。
`0x04`: GNSS + Wi-Fi スキャンがタイムアウトしました。
`0x05`: Bluetooth スキャンがタイムアウトしました。
`0x06`: Bluetooth + Wi-Fi スキャンがタイムアウトしました。
`0x07`: Bluetooth + GNSS スキャンがタイムアウトしました。
`0x08`: Bluetooth + Wi-Fi + GNSS スキャンがタイムアウトしました。
`0x09`: Location Server が GNSS 位置情報の解析に失敗しました。
`0x0A`: Location Server が Wi-Fi 位置情報の解析に失敗しました。
`0x0B`: Location Server が Bluetooth 位置情報の解析に失敗しました。
`0x0C`: 精度が低いため位置情報の解析に失敗しました。
`0x0D`: 時刻同期に失敗しました。
`0x0E`: 古い Almanac が原因で失敗しました。
`0x0F`: GNSS + Bluetooth スキャンがタイムアウトしました。 | +| 3~4 | イベントステータス | uint16 | 0100 | `0x0000` = イベント未発生
Bit 0: false
Bit 1: 移動開始イベント
Bit 2: 移動終了イベント
Bit 3: 静止イベント
Bit 4: 衝撃イベント
Bit 5: 温度イベント
Bit 6: 光イベント
Bit 7: SOS イベント
Bit 8: 1 回押下イベント
Bit 9: 分解イベント

16 進数への変換:
`0x0001`: 移動開始イベント
`0x0002`: 移動終了イベント
`0x0004`: 静止イベント
`0x0008`: 衝撃イベント
`0x0010`: 温度イベント
`0x0020`: 光イベント
`0x0040`: SOS イベント
`0x0080`: 1 回押下イベント
`0x0100`: 分解イベント | +| 5~8 | UTC タイムスタンプ | uint32 | 694B3DB0 | `0x694B3DB0` = 1766538672(DEC) 秒

UTC 時刻に変換:
2025-12-24 01:11:12 | +| 9 | バッテリーレベル | uint8 | 62 | `0x62` = 98% | + +## ダウンリンクパケット, FPort=5 + +トラッカーは LoRaWAN をサポートしており、いくつかのコマンドをダウンリンクしてパラメータを調整できます。デバイスが休止状態の場合、ダウンリンクコマンドは、デバイスが次回データをアップロードするために起床したときに有効になります。 + +LoRaWAN Class A の仕様上、ダウンリンクウィンドウはアップリンク後にのみ開くため、コマンドはリアルタイムではありません。例えば、報告間隔が 10 分に設定されている場合、デバイスが次の送信ウィンドウでダウンリンクコマンドを受信するまでに最大 10 分かかる可能性があります。 + +**注意: FPort=5** + +### デバイスステータス要求パケット (0x8F) + +|0x8F| +| - | +|ID| + +例: + +8F: 最新のデバイスステータスおよび位置情報パケットを要求します。 + +### 動作モード & 位置情報戦略の設定 (0x90) + +|0x90|Byte2|Byte3|Byte4~5|Byte6~7|Byte8~9| +| - | :- | :- | :- | :- | :- | +|ID|動作モード|位置情報戦略|ハートビート間隔|周期モードアップリンク間隔|イベントモードアップリンク間隔| + +|Byte10|Byte11|Byte12|Byte13|Byte14|Byte15~30| +| - | - | - | - | - | :- | +|3 軸加速度センサー有効化|分解アラーム有効化|GNSS スキャンタイムアウト (S)|iBeacon スキャンタイムアウト (S)|UUID フィルタ有効バイト数|UUID フィルタ| + +注意: +ハートビート間隔 / 周期モードアップリンク間隔 / イベントモードアップリンク間隔の単位:**分** + +例: + +`90 01 01 02d0 0014 0005 01 01 1e 0a 10 00000000000000000000000000000000` + + +|**Byte**|**Value**|**Type**|**Raw Data**|**Description**| +| - | - | - | - | - | +|1|フレーム ID|uint8|90|90 はパケット ID です| +|2|動作モード|uint8|01|01 = 周期モード
`00`: スタンバイモード
`01`: 周期モード
`02`: イベントモード| +|3|位置情報戦略|uint8|01|`00`: GNSS のみ
`01`: Wi-Fi のみ
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: Bluetooth のみ
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +|4~5|ハートビート間隔 | uint16 | 02d0 | `0x02D0` = 720 分| +|6~7|周期モードアップリンク間隔|uint16|0014|`0x0014` = 20 分 | +|8~9|イベントモードアップリンク間隔|uint16|0005|`0x0005` = 5 分
イベントが発生しない場合、データは 5 分ごとにアップロードされます。
| +|10|3 軸加速度センサー有効化|uint8|01|`00`: 無効
`01`: 有効| +|11|分解アラーム有効化|uint8|01|`00`: 無効
`01`: 有効| +|12|GNSS スキャンタイムアウト|uint8|1E|`0x1E` = 30 秒 | +|13|iBeacon スキャンタイムアウト|uint8|0A|`0x0A` = 10 秒 | +|14|UUID フィルタ有効バイト数|uint8|10| UUID フィルタ内の有効バイト数 (0–16)| +|15~30|UUID フィルタ| 16 bytes | 0000000000000000
0000000000000000 | 16 バイトの Bluetooth UUID フィルタ。先頭の N バイトのみ(byte30 で定義)が有効| + + +### イベントモードしきい値の設定 (0x91) + +|0x91|Byte2|Byte3~4|Byte5~6|Byte7|Byte8~9| +| - | :- | :- | :- | :- | :- | +|ID|モーションイベントを有効化|3軸モーションしきい値|モーション時のアップリンク間隔|静止イベントを有効化|静止タイムアウト| + +|Byte10|Byte11~12| +| - | :- | +|ショックイベントを有効化|3軸ショックしきい値| + + +例: + +`91 01 001e 0005 01 01 2c` + +|**Byte**|**値**|**型**|**生データ**|**説明**| +| - | - | - | - | - | +|1|フレーム ID|uint8|91|91 はパケット ID です| +|2|モーションイベントを有効化|uint8|01|`00`: 無効
`01`: 有効| +|3~4|3軸モーションしきい値|uint16|001e|`0x001E` = 30 mg
加速度が 30 mg を超えると、デバイスは動作中であると判断します
| +|5~6|モーション時のアップリンク間隔|uint16|0005|`0x0005` = 5 分
モーションが検出されると、報告間隔は 5 分になります
| +|7|静止イベントを有効化|uint8|01|`00`: 無効
`01`: 有効| +|8~9|静止タイムアウト|uint16|012c|`0x012C` = 300 分
デバイスが 300 分以上静止したままの場合、静止イベントがトリガーされます
| +|10|ショックイベントを有効化|uint8|01|`00`: 無効
`01`: 有効| +|11~12|3軸ショックしきい値|uint16|012c|`0x012C` = 300 mg
加速度が 300 mg を超えると、ショックイベントがトリガーされます
| + +### デバイスステータスパケットの要求 (0x92) + +|0x92| +| - | +|ID| + +例: + +92: GNSS 位置情報の取得を強制します。 + +### 動作モード & 測位戦略 & イベントモードしきい値の設定 (0x97) + +|0x97|Byte2|Byte3|Byte4~5|Byte6~7|Byte8~9| +| - | :- | :- | :- | :- | :- | +|ID|動作モード|測位戦略|ハートビート間隔|周期モードアップリンク間隔|イベントモードアップリンク間隔| + +|Byte10|Byte11|Byte12|Byte13|Byte14|Byte15~30| +| - | :- | :- | :- | :- | :- | +|3軸加速度センサを有効化|分解アラームを有効化|GNSS スキャンタイムアウト|iBeacon スキャンタイムアウト|UUID フィルタ有効バイト数|UUID フィルタ| + +#### モーションイベント設定 +|Byte31|Byte32~33|Byte34~35| +| - | :- | :- | +|モーションイベントを有効化|3軸モーションしきい値|モーション時のアップリンク間隔| + +#### 静止イベント設定 +|Byte36|Byte37~38| +| - | :- | +|静止イベントを有効化|静止タイムアウト| + + +#### ショックイベント設定 +|Byte39|Byte40~41| +| - | :- | +|ショックイベントを有効化|3軸ショックしきい値| + +例: + +`97 01 02 003c 001e 000a 01 01 0a 05 10 00000000000000000000000000000000 01 001e 0005 01 012c 01 012c` + +|**Byte**|**値**|**型**|**生データ**|**説明**| +| - | - | - | - | - | +|1|フレーム ID|uint8|97|97 はパケット ID です| +|2|動作モード|uint8|01|`00`: スタンバイモード
`01`: 周期モード
`02`: イベントモード| +|3|測位戦略|uint8|02|`00`: GNSS のみ
`01`: Wi-Fi のみ
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: Bluetooth のみ
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +|4~5|ハートビート間隔|uint16|003c|`0x003C` = 60 秒| +|6~7|周期モードアップリンク間隔|uint16|001e|`0x001E` = 30 秒| +|8~9|イベントモードアップリンク間隔|uint16|000a|`0x000A` = 10 分
イベントがトリガーされない場合、データは 10 分ごとにアップロードされます。
| +|10|3軸加速度センサを有効化|uint8|01|`00`: 無効
`01`: 有効| +|11|分解アラームを有効化|uint8|01|`00`: 無効
`01`: 有効| +|12|GNSS スキャンタイムアウト|uint8|0a|`0x0A` = 10 秒| +|13|iBeacon スキャンタイムアウト|uint8|05|`0x05` = 5 秒| +|14|UUID フィルタ有効バイト数|uint8|10|`0x10` = 16 バイト| +|15~30|UUID フィルタ|byte[16]|0000000000000000
0000000000000000|UUID フィルタ値 (16 バイト)
| +|31|モーションイベントを有効化|uint8|01|`00`: 無効
`01`: 有効| +|32~33|3軸モーションしきい値|uint16|001e|`0x001E` = 30 mg | +|34~35|モーション時のアップリンク間隔|uint16|0005|`0x0005` = 5 分
モーションが検出されると、報告間隔は 5 分になります| +|36|静止イベントを有効化|uint8|01|`00`: 無効
`01`: 有効| +|37~38|静止タイムアウト|uint16|012c|`0x012C` = 300 分 | +|39|ショックイベントを有効化|uint8|01|`00`: 無効
`01`: 有効| +|40~41|3軸ショックしきい値|uint16|012c|`0x012C` = 300 mg | + +## 技術サポート & 製品ディスカッション + +弊社製品をお選びいただきありがとうございます。弊社は、製品をできるだけスムーズにご利用いただけるよう、さまざまなサポートを提供しています。お好みやニーズに応じて選択いただける、複数のコミュニケーションチャネルをご用意しています。 + +
+ + +
+ +
+ + +
\ No newline at end of file diff --git a/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/ja_SenseCAP_T2000_intro.md b/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/ja_SenseCAP_T2000_intro.md index e4e7a083c9429..edee83623a4eb 100644 --- a/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/ja_SenseCAP_T2000_intro.md +++ b/sites/ja/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/ja_SenseCAP_T2000_intro.md @@ -2,31 +2,33 @@ description: SenseCAP T2000 トラッカー title: SenseCAP T2000 トラッカー keywords: - - Tracker + - トラッカー - SenseCAP image: https://files.seeedstudio.com/wiki/wiki-platform/S-tempor.png slug: /sensecap_t2000_tracker last_update: - date: 1/28/2026 + date: 3/12/2026 author: Janet -createdAt: '2025-12-01' -updatedAt: '2026-03-03' +createdAt: '2025-11-27' +updatedAt: '2026-03-12' url: https://wiki.seeedstudio.com/ja/sensecap_t2000_tracker/ ---

pir

-[**SenseCAP T2000 トラッカー**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html)は、産業グレードのLoRaWAN®アセットトラッカーで、GNSS、Bluetooth、Wi-Fi測位をサポートし、屋内外環境での信頼性の高い追跡を実現します。IP67保護、動作状態を検出する内蔵3軸加速度計、デバイスが取り外された場合に最優先アラームをトリガーするタンパー防止ボタンを備えています。T2000-AとT2000-Bは長時間のバッテリー動作をサポートし、充電式バッテリーを搭載したソーラー電源のT2000-Cは継続的な屋外使用を保証し、このシリーズを長期間のメンテナンスフリーなアセット追跡に最適にしています。 +[**SenseCAP T2000 Tracker**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html) は、産業グレードの LoRaWAN® アセットトラッカーであり、GNSS、Bluetooth、Wi-Fi 位置測位をサポートし、屋内外の環境において信頼性の高いトラッキングを実現します。IP67 保護等級、動作状態を検知する内蔵 3 軸加速度センサー、そしてデバイスが取り外された際に最優先アラームをトリガーするタンパー防止ボタンを備えています。T2000-A と T2000-B は長期間動作するバッテリー駆動に対応し、充電式バッテリーを備えたソーラー駆動の T2000-C は屋外での連続使用を可能にすることで、このシリーズを長期的かつメンテナンスフリーなアセットトラッキングに最適なものとしています。

SenseCAP T2000 トラッカーのカタログ

-### LoRaWAN®ネットワークサーバーとの統合 +### LoRaWAN® ネットワークサーバーとの統合
The Things Network @@ -34,9 +36,9 @@ url: https://wiki.seeedstudio.com/ja/sensecap_t2000_tracker/ AWS IoT Core
-## 技術サポート & 製品ディスカッション +## 技術サポートと製品ディスカッション -弊社製品をお選びいただき、ありがとうございます!弊社製品での体験が可能な限りスムーズになるよう、さまざまなサポートを提供いたします。異なる好みやニーズに対応するため、複数のコミュニケーションチャンネルを提供しています。 +弊社製品をお選びいただきありがとうございます。私たちは、お客様が製品をできるだけスムーズにご利用いただけるよう、さまざまなサポートを提供しています。お好みやニーズに応じてお選びいただける、複数のコミュニケーションチャネルをご用意しています。
diff --git a/sites/ja/docs/Sensor/SenseCAP/ja_SenseCAP_Decoder.md b/sites/ja/docs/Sensor/SenseCAP/ja_SenseCAP_Decoder.md index 1381e93502cb5..cc6bec1171659 100644 --- a/sites/ja/docs/Sensor/SenseCAP/ja_SenseCAP_Decoder.md +++ b/sites/ja/docs/Sensor/SenseCAP/ja_SenseCAP_Decoder.md @@ -1,23 +1,23 @@ --- -description: SenseCAP_Decoder -title: SenseCAP Decoder +description: SenseCAP デコーダ +title: SenseCAP デコーダ keywords: - SenseCAP_Decoder image: https://files.seeedstudio.com/wiki/wiki-platform/S-tempor.png slug: /SenseCAP_Decoder last_update: - date: 1/26/2026 + date: 3/12/2026 author: Janet createdAt: '2023-08-24' -updatedAt: '2026-03-03' +updatedAt: '2026-03-12' url: https://wiki.seeedstudio.com/ja/SenseCAP_Decoder/ --- -SenseCAP デコーダーは、SenseCAP LoRaWAN® デバイスから送信される LoRaWAN メッセージをデコードするために使用されます。デコード後、ユーザーのアプリケーションはより親しみやすく読みやすいメッセージを取得できます。 +SenseCAP デコーダは、SenseCAP LoRaWAN® デバイスから送信される LoRaWAN メッセージをデコードするために使用されます。デコード後、ユーザーのアプリケーションは、より扱いやすく読みやすいメッセージを取得できます。 -### SenseCAP T1000 Tracker +### SenseCAP T1000 トラッカー -[**SenseCAP T1000**](https://www.seeedstudio.com/sensecap-t1000-tracker?utm_source=emailsig&utm_medium=emailsig&utm_campaign=emailsig) は、GNSS/Wi-Fi/Bluetooth を利用して屋内外での正確な位置追跡を行うコンパクトな LoRaWAN® トラッカーです。自己地理適応機能、ローカルデータストレージ、そして数ヶ月間の印象的なバッテリー寿命を誇ります。さらに、温度、光、モーションセンサーを搭載しており、様々な位置ベースアプリケーションに最適です。 +[**SenseCAP T1000**](https://www.seeedstudio.com/sensecap-t1000-tracker?utm_source=emailsig&utm_medium=emailsig&utm_campaign=emailsig) は、GNSS/Wi-Fi/Bluetooth を利用して屋内外の正確な位置情報を追跡する、コンパクトな LoRaWAN® トラッカーです。自己地理適応機能、ローカルデータストレージ、数か月に及ぶ優れたバッテリー寿命を備えています。さらに、温度、光、モーションセンサーも搭載しており、さまざまな位置情報ベースのアプリケーションに最適です。

pir

@@ -27,11 +27,11 @@ SenseCAP デコーダーは、SenseCAP LoRaWAN® デバイスから送信され
-#### デコーダー +#### デコーダ
-TTN(ChirpStack V4)向け +TTN 用(ChirpStack V4) ```cpp function decodeUplink (input) { @@ -49,833 +49,6 @@ function decodeUplink (input) { decoded.messages.push({fport: fport, payload: bytesString}) return { data: decoded } } - if (fport !== 5) { - decoded.valid = false - return { data: decoded } - } - let measurement = messageAnalyzed(originMessage) - if (measurement.length === 0) { - decoded.valid = false - return { data: decoded } - } - - for (let message of measurement) { - if (message.length === 0) { - continue - } - let elements = [] - for (let element of message) { - if (element.errorCode) { - decoded.err = element.errorCode - decoded.errMessage = element.error - } else { - elements.push(element) - } - } - if (elements.length > 0) { - decoded.messages.push(elements) - } - } - // decoded.messages = measurement - return { data: decoded } -} - -function messageAnalyzed (messageValue) { - try { - let frames = unpack(messageValue) - let measurementResultArray = [] - for (let i = 0; i < frames.length; i++) { - let item = frames[i] - let dataId = item.dataId - let dataValue = item.dataValue - let measurementArray = deserialize(dataId, dataValue) - measurementResultArray.push(measurementArray) - } - return measurementResultArray - } catch (e) { - return e.toString() - } -} - -function unpack (messageValue) { - let frameArray = [] - - for (let i = 0; i < messageValue.length; i++) { - let remainMessage = messageValue - let dataId = remainMessage.substring(0, 2).toUpperCase() - let dataValue - let dataObj = {} - let packageLen - switch (dataId) { - case '01': - packageLen = 94 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '02': - packageLen = 32 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '03': - packageLen = 64 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '04': - packageLen = 20 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '05': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '06': - packageLen = 44 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '07': - packageLen = 84 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '08': - packageLen = 70 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '09': - packageLen = 36 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0A': - packageLen = 76 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0B': - packageLen = 62 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0C': - packageLen = 2 - if (remainMessage.length < packageLen) { - return frameArray - } - break - case '0D': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0E': - packageLen = getInt(remainMessage.substring(8, 10)) * 2 + 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, 8) + remainMessage.substring(10, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0F': - packageLen = 34 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '10': - packageLen = 26 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '11': - packageLen = 28 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - default: - return frameArray - } - if (dataValue.length < 2) { - break - } - frameArray.push(dataObj) - } - return frameArray -} - -function deserialize (dataId, dataValue) { - let measurementArray = [] - let eventList = [] - let measurement = {} - let collectTime = 0 - let groupId = 0 - let shardFlag = {} - let payload = '' - let result = [] - let dataArr = [] - switch (dataId) { - case '01': - measurementArray = getUpShortInfo(dataValue) - measurementArray.push(...getMotionSetting(dataValue.substring(30, 40))) - measurementArray.push(...getStaticSetting(dataValue.substring(40, 46))) - measurementArray.push(...getShockSetting(dataValue.substring(46, 52))) - measurementArray.push(...getTempSetting(dataValue.substring(52, 72))) - measurementArray.push(...getLightSetting(dataValue.substring(72, 92))) - break - case '02': - measurementArray = getUpShortInfo(dataValue) - break - case '03': - measurementArray.push(...getMotionSetting(dataValue.substring(0, 10))) - measurementArray.push(...getStaticSetting(dataValue.substring(10, 16))) - measurementArray.push(...getShockSetting(dataValue.substring(16, 22))) - measurementArray.push(...getTempSetting(dataValue.substring(22, 42))) - measurementArray.push(...getLightSetting(dataValue.substring(42, 62))) - break - case '04': - let interval = 0 - let workMode = getInt(dataValue.substring(0, 2)) - let heartbeatInterval = getMinsByMin(dataValue.substring(4, 8)) - let periodicInterval = getMinsByMin(dataValue.substring(8, 12)) - let eventInterval = getMinsByMin(dataValue.substring(12, 16)) - switch (workMode) { - case 0: - interval = heartbeatInterval - break - case 1: - interval = periodicInterval - break - case 2: - interval = eventInterval - break - } - measurementArray = [ - {measurementId: '3940', type: 'Work Mode', measurementValue: workMode}, - {measurementId: '3942', type: 'Heartbeat Interval', measurementValue: heartbeatInterval}, - {measurementId: '3943', type: 'Periodic Interval', measurementValue: periodicInterval}, - {measurementId: '3944', type: 'Event Interval', measurementValue: eventInterval}, - {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(16, 18))}, - {measurementId: '3900', type: 'Uplink Interval', measurementValue: interval} - ] - break; - case '05': - measurementArray = [ - {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(0, 2))}, - {measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(dataValue.substring(2, 4))}, - {measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(dataValue.substring(4, 6))}, - {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(6, 8))} - ] - break - case '06': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} - ] - break - case '07': - eventList = getEventStatus(dataValue.substring(0, 6)) - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} - ] - break - case '08': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} - ] - break - case '09': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} - ] - break - case '0A': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} - ] - break - case '0B': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, - ] - break - case '0D': - let errorCode = getInt(dataValue) - let error = '' - switch (errorCode) { - case 1: - error = 'FAILED TO OBTAIN THE UTC TIMESTAMP' - break - case 2: - error = 'ALMANAC TOO OLD' - break - case 3: - error = 'DOPPLER ERROR' - break - } - measurementArray.push({errorCode, error}) - break - case '0E': - shardFlag = getShardFlag(dataValue.substring(0, 2)) - groupId = getInt(dataValue.substring(2, 6)) - payload = dataValue.substring(6) - measurement = { - measurementId: '6152', - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'gnss-ng payload', - measurementValue: payload - } - measurementArray.push(measurement) - break - case '0F': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - shardFlag = getShardFlag(dataValue.substring(26, 28)) - groupId = getInt(dataValue.substring(28, 32)) - measurementArray.push({ - measurementId: '4200', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Event Status', - measurementValue: getEventStatus(dataValue.substring(0, 6)) - }) - measurementArray.push({ - measurementId: '4097', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) - }) - measurementArray.push({ - measurementId: '4199', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) - }) - measurementArray.push({ - measurementId: '3000', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) - }) - break - case '10': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - shardFlag = getShardFlag(dataValue.substring(18, 20)) - groupId = getInt(dataValue.substring(20, 24)) - measurementArray.push({ - measurementId: '4200', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Event Status', - measurementValue: getEventStatus(dataValue.substring(0, 6)) - }) - measurementArray.push({ - measurementId: '3000', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(16, 18)) - }) - break - case '11': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray.push({ - measurementId: '3576', - timestamp: collectTime, - type: 'Positing Status', - measurementValue: '' + getPositingStatus(dataValue.substring(0, 2)) - }) - measurementArray.push({ - timestamp: collectTime, - measurementId: '4200', - type: 'Event Status', - measurementValue: getEventStatus(dataValue.substring(2, 8)) - }) - if (!isNaN(parseFloat(getSensorValue(dataValue.substring(16, 20), 10)))) { - measurementArray.push({ - timestamp: collectTime, - measurementId: '4097', - type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) - }) - } - if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { - measurementArray.push({ - timestamp: collectTime, - measurementId: '4199', - type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) - }) - } - measurementArray.push({ - timestamp: collectTime, - measurementId: '3000', - type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) - }) - break - } - return measurementArray -} - -function getMotionId (str) { - return getInt(str) -} - -function getPositingStatus (str) { - return getInt(str) -} - -function getUpShortInfo (messageValue) { - return [ - { - measurementId: '3000', type: 'Battery', measurementValue: getBattery(messageValue.substring(0, 2)) - }, { - measurementId: '3502', type: 'Firmware Version', measurementValue: getSoftVersion(messageValue.substring(2, 6)) - }, { - measurementId: '3001', type: 'Hardware Version', measurementValue: getHardVersion(messageValue.substring(6, 10)) - }, { - measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(messageValue.substring(10, 12)) - }, { - measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(messageValue.substring(12, 14)) - }, { - measurementId: '3942', type: 'Heartbeat Interval', measurementValue: getMinsByMin(messageValue.substring(14, 18)) - }, { - measurementId: '3943', type: 'Periodic Interval', measurementValue: getMinsByMin(messageValue.substring(18, 22)) - }, { - measurementId: '3944', type: 'Event Interval', measurementValue: getMinsByMin(messageValue.substring(22, 26)) - }, { - measurementId: '3945', type: 'Sensor Enable', measurementValue: getInt(messageValue.substring(26, 28)) - }, { - measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(messageValue.substring(28, 30)) - } - ] -} - -function getMotionSetting (str) { - return [ - {measurementId: '3946', type: 'Motion Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3947', type: 'Any Motion Threshold', measurementValue: getSensorValue(str.substring(2, 6), 1)}, - {measurementId: '3948', type: 'Motion Start Interval', measurementValue: getMinsByMin(str.substring(6, 10))}, - ] -} - -function getStaticSetting (str) { - return [ - {measurementId: '3949', type: 'Static Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3950', type: 'Device Static Timeout', measurementValue: getMinsByMin(str.substring(2, 6))} - ] -} - -function getShockSetting (str) { - return [ - {measurementId: '3951', type: 'Shock Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3952', type: 'Shock Threshold', measurementValue: getInt(str.substring(2, 6))} - ] -} - -function getTempSetting (str) { - return [ - {measurementId: '3953', type: 'Temp Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3954', type: 'Event Temp Interval', measurementValue: getMinsByMin(str.substring(2, 6))}, - {measurementId: '3955', type: 'Event Temp Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))}, - {measurementId: '3956', type: 'Temp ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)}, - {measurementId: '3957', type: 'Temp ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)}, - {measurementId: '3958', type: 'Temp Warning Type', measurementValue: getInt(str.substring(18, 20))} - ] -} - -function getLightSetting (str) { - return [ - {measurementId: '3959', type: 'Light Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3960', type: 'Event Light Interval', measurementValue: getMinsByMin(str.substring(2, 6))}, - {measurementId: '3961', type: 'Event Light Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))}, - {measurementId: '3962', type: 'Light ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)}, - {measurementId: '3963', type: 'Light ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)}, - {measurementId: '3964', type: 'Light Warning Type', measurementValue: getInt(str.substring(18, 20))} - ] -} - -function getShardFlag (str) { - let bitStr = getByteArray(str) - return { - count: parseInt(bitStr.substring(0, 4), 2), - index: parseInt(bitStr.substring(4), 2) - } -} - -function getBattery (batteryStr) { - return loraWANV2DataFormat(batteryStr) -} -function getSoftVersion (softVersion) { - return `${loraWANV2DataFormat(softVersion.substring(0, 2))}.${loraWANV2DataFormat(softVersion.substring(2, 4))}` -} -function getHardVersion (hardVersion) { - return `${loraWANV2DataFormat(hardVersion.substring(0, 2))}.${loraWANV2DataFormat(hardVersion.substring(2, 4))}` -} - -function getSecondsByInt (str) { - return getInt(str) -} - -function getMinsByMin (str) { - return getInt(str) -} - -function getSensorValue (str, dig) { - if (str === '8000') { - return null - } else { - return loraWANV2DataFormat(str, dig) - } -} - -function bytes2HexString (arrBytes) { - var str = '' - for (var i = 0; i < arrBytes.length; i++) { - var tmp - var num = arrBytes[i] - if (num < 0) { - tmp = (255 + num + 1).toString(16) - } else { - tmp = num.toString(16) - } - if (tmp.length === 1) { - tmp = '0' + tmp - } - str += tmp - } - return str -} -function loraWANV2DataFormat (str, divisor = 1) { - let strReverse = bigEndianTransform(str) - let str2 = toBinary(strReverse) - if (str2.substring(0, 1) === '1') { - let arr = str2.split('') - let reverseArr = arr.map((item) => { - if (parseInt(item) === 1) { - return 0 - } else { - return 1 - } - }) - str2 = parseInt(reverseArr.join(''), 2) + 1 - return '-' + str2 / divisor - } - return parseInt(str2, 2) / divisor -} - -function bigEndianTransform (data) { - let dataArray = [] - for (let i = 0; i < data.length; i += 2) { - dataArray.push(data.substring(i, i + 2)) - } - return dataArray -} - -function toBinary (arr) { - let binaryData = arr.map((item) => { - let data = parseInt(item, 16) - .toString(2) - let dataLength = data.length - if (data.length !== 8) { - for (let i = 0; i < 8 - dataLength; i++) { - data = `0` + data - } - } - return data - }) - return binaryData.toString().replace(/,/g, '') -} - -function getSOSMode (str) { - return loraWANV2DataFormat(str) -} - -function getMacAndRssiObj (pair) { - let pairs = [] - if (pair.length % 14 === 0) { - for (let i = 0; i < pair.length; i += 14) { - let mac = getMacAddress(pair.substring(i, i + 12)) - if (mac) { - let rssi = getInt8RSSI(pair.substring(i + 12, i + 14)) - pairs.push({mac: mac, rssi: rssi}) - } else { - continue - } - } - } - return pairs -} - -function getMacAddress (str) { - if (str.toLowerCase() === 'ffffffffffff') { - return null - } - let macArr = [] - for (let i = 1; i < str.length; i++) { - if (i % 2 === 1) { - macArr.push(str.substring(i - 1, i + 1)) - } - } - let mac = '' - for (let i = 0; i < macArr.length; i++) { - mac = mac + macArr[i] - if (i < macArr.length - 1) { - mac = mac + ':' - } - } - return mac -} - -function getInt8RSSI (str) { - return loraWANV2DataFormat(str) -} - -function getInt (str) { - return parseInt(str, 16) -} - -function getEventStatus (str) { - // return getInt(str) - let bitStr = getByteArray(str) - let bitArr = [] - for (let i = 0; i < bitStr.length; i++) { - bitArr[i] = bitStr.substring(i, i + 1) - } - bitArr = bitArr.reverse() - let event = [] - for (let i = 0; i < bitArr.length; i++) { - if (bitArr[i] !== '1') { - continue - } - switch (i){ - case 0: - event.push({id:1, eventName:"Start moving event."}) - break - case 1: - event.push({id:2, eventName:"End movement event."}) - break - case 2: - event.push({id:3, eventName:"Motionless event."}) - break - case 3: - event.push({id:4, eventName:"Shock event."}) - break - case 4: - event.push({id:5, eventName:"Temperature event."}) - break - case 5: - event.push({id:6, eventName:"Light event."}) - break - case 6: - event.push({id:7, eventName:"SOS event."}) - break - case 7: - event.push({id:8, eventName:"Press once event."}) - break - } - } - return event -} - -function getByteArray (str) { - let bytes = [] - for (let i = 0; i < str.length; i += 2) { - bytes.push(str.substring(i, i + 2)) - } - return toBinary(bytes) -} - -function getWorkingMode (workingMode) { - return getInt(workingMode) -} - -function getPositioningStrategy (strategy) { - return getInt(strategy) -} - -function getUTCTimestamp(str){ - return parseInt(loraWANV2PositiveDataFormat(str)) * 1000 -} - -function loraWANV2PositiveDataFormat (str, divisor = 1) { - let strReverse = bigEndianTransform(str) - let str2 = toBinary(strReverse) - return parseInt(str2, 2) / divisor -} -``` - -
- -
- -Helium 向け - -```cpp -function Decoder (bytes, port) { - const bytesString = bytes2HexString(bytes) - const originMessage = bytesString.toLocaleUpperCase() - const fport = parseInt(port) - const decoded = { - valid: true, - err: 0, - payload: bytesString, - messages: [] - } - - if (fport === 199 || fport === 192) { - decoded.messages.push({fport: fport, payload: bytesString}) - return { data: decoded } - } - if (fport !== 5) { - decoded.valid = false - return { data: decoded } - } - let measurement = messageAnalyzed(originMessage) if (measurement.length === 0) { decoded.valid = false @@ -899,7 +72,6 @@ function Decoder (bytes, port) { decoded.messages.push(elements) } } - // decoded.messages = measurement return { data: decoded } } @@ -922,7 +94,6 @@ function messageAnalyzed (messageValue) { function unpack (messageValue) { let frameArray = [] - for (let i = 0; i < messageValue.length; i++) { let remainMessage = messageValue let dataId = remainMessage.substring(0, 2).toUpperCase() @@ -931,148 +102,93 @@ function unpack (messageValue) { let packageLen switch (dataId) { case '01': - packageLen = 94 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 94) + messageValue = remainMessage.substring(94) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '02': - packageLen = 32 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 32) + messageValue = remainMessage.substring(32) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '03': - packageLen = 64 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 64) + messageValue = remainMessage.substring(64) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '04': - packageLen = 20 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 20) + messageValue = remainMessage.substring(20) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '05': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 10) + messageValue = remainMessage.substring(10) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '06': - packageLen = 44 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 44) + messageValue = remainMessage.substring(44) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '07': - packageLen = 84 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 84) + messageValue = remainMessage.substring(84) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '08': - packageLen = 70 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 70) + messageValue = remainMessage.substring(70) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '09': - packageLen = 36 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 36) + messageValue = remainMessage.substring(36) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0A': - packageLen = 76 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 76) + messageValue = remainMessage.substring(76) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0B': - packageLen = 62 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 62) + messageValue = remainMessage.substring(62) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0C': - packageLen = 2 - if (remainMessage.length < packageLen) { - return frameArray - } break case '0D': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 10) + messageValue = remainMessage.substring(10) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0E': packageLen = getInt(remainMessage.substring(8, 10)) * 2 + 10 - if (remainMessage.length < packageLen) { - return frameArray - } dataValue = remainMessage.substring(2, 8) + remainMessage.substring(10, packageLen) messageValue = remainMessage.substring(packageLen) dataObj = { @@ -1080,34 +196,50 @@ function unpack (messageValue) { } break case '0F': - packageLen = 34 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 34) + messageValue = remainMessage.substring(34) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '10': - packageLen = 26 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 26) + messageValue = remainMessage.substring(26) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '11': - packageLen = 28 - if (remainMessage.length < packageLen) { - return frameArray + dataValue = remainMessage.substring(2, 28) + messageValue = remainMessage.substring(28) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + break + case '1A': + dataValue = remainMessage.substring(2, 56) + messageValue = remainMessage.substring(56) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue + } + break + case '1B': + dataValue = remainMessage.substring(2, 96) + messageValue = remainMessage.substring(96) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue + } + break + case '1C': + dataValue = remainMessage.substring(2, 82) + messageValue = remainMessage.substring(82) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue + } + break + case '1D': + dataValue = remainMessage.substring(2, 40) + messageValue = remainMessage.substring(40) dataObj = { 'dataId': dataId, 'dataValue': dataValue } @@ -1131,8 +263,7 @@ function deserialize (dataId, dataValue) { let groupId = 0 let shardFlag = {} let payload = '' - let result = [] - let dataArr = [] + let motionId = '' switch (dataId) { case '01': measurementArray = getUpShortInfo(dataValue) @@ -1188,59 +319,65 @@ function deserialize (dataId, dataValue) { break case '06': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '4197', timestamp: collectTime, motionId: motionId, type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, + {measurementId: '4198', timestamp: collectTime, motionId: motionId, type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, + {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} ] break case '07': eventList = getEventStatus(dataValue.substring(0, 6)) collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5001', timestamp: collectTime, motionId: motionId, type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, + {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} ] break case '08': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5002', timestamp: collectTime, motionId: motionId, type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, + {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} ] break case '09': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '4197', timestamp: collectTime, motionId: motionId, type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, + {measurementId: '4198', timestamp: collectTime, motionId: motionId, type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} ] break case '0A': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5001', timestamp: collectTime, motionId, type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} ] break case '0B': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5002', timestamp: collectTime, motionId, type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, ] break case '0D': @@ -1277,10 +414,11 @@ function deserialize (dataId, dataValue) { collectTime = getUTCTimestamp(dataValue.substring(8, 16)) shardFlag = getShardFlag(dataValue.substring(26, 28)) groupId = getInt(dataValue.substring(28, 32)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray.push({ measurementId: '4200', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, @@ -1290,42 +428,43 @@ function deserialize (dataId, dataValue) { measurementArray.push({ measurementId: '4097', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) + measurementValue: getSensorValue(dataValue.substring(16, 20), 10) }) measurementArray.push({ measurementId: '4199', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) + measurementValue: getSensorValue(dataValue.substring(20, 24)) }) measurementArray.push({ measurementId: '3000', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) + measurementValue: getBattery(dataValue.substring(24, 26)) }) break case '10': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) shardFlag = getShardFlag(dataValue.substring(18, 20)) groupId = getInt(dataValue.substring(20, 24)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray.push({ measurementId: '4200', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, @@ -1335,12 +474,12 @@ function deserialize (dataId, dataValue) { measurementArray.push({ measurementId: '3000', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(16, 18)) + measurementValue: getBattery(dataValue.substring(16, 18)) }) break case '11': @@ -1348,8 +487,8 @@ function deserialize (dataId, dataValue) { measurementArray.push({ measurementId: '3576', timestamp: collectTime, - type: 'Positing Status', - measurementValue: '' + getPositingStatus(dataValue.substring(0, 2)) + type: 'Positioning Status', + measurementValue: getPositingStatus(dataValue.substring(0, 2)) }) measurementArray.push({ timestamp: collectTime, @@ -1362,7 +501,7 @@ function deserialize (dataId, dataValue) { timestamp: collectTime, measurementId: '4097', type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) + measurementValue: getSensorValue(dataValue.substring(16, 20), 10) }) } if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { @@ -1370,14 +509,112 @@ function deserialize (dataId, dataValue) { timestamp: collectTime, measurementId: '4199', type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) + measurementValue: getSensorValue(dataValue.substring(20, 24)) }) } measurementArray.push({ timestamp: collectTime, measurementId: '3000', type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) + measurementValue: getBattery(dataValue.substring(24, 26)) + }) + break + case '1A': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) + measurementArray = [ + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '4197', timestamp: collectTime, motionId, type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, + {measurementId: '4198', timestamp: collectTime, motionId, type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, + {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, + {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(40, 44))}, + {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(44, 48))}, + {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(48, 52))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(52, 54))}, + ] + break + case '1B': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) + measurementArray = [ + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5001', timestamp: collectTime, motionId, type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, + {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, + {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(80, 84))}, + {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(84, 88))}, + {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(88, 92))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(92, 94))} + ] + break + case '1C': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) + measurementArray = [ + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5002', timestamp: collectTime, motionId, type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, + {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, + {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(66, 70))}, + {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(70, 74))}, + {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(74, 78))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(78, 80))} + ] + break + case '1D': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + measurementArray.push({ + measurementId: '3576', + timestamp: collectTime, + type: 'Positioning Status', + measurementValue: getPositingStatus(dataValue.substring(0, 2)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '4200', + type: 'Event Status', + measurementValue: getEventStatus(dataValue.substring(2, 8)) + }) + if (!isNaN(parseFloat(getSensorValue(dataValue.substring(16, 20), 10)))) { + measurementArray.push({ + timestamp: collectTime, + measurementId: '4097', + type: 'Air Temperature', + measurementValue: getSensorValue(dataValue.substring(16, 20), 10) + }) + } + if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { + measurementArray.push({ + timestamp: collectTime, + measurementId: '4199', + type: 'Light', + measurementValue: getSensorValue(dataValue.substring(20, 24)) + }) + } + measurementArray.push({ + timestamp: collectTime, + measurementId: '4210', + type: 'AccelerometerX', + measurementValue: getSensorValue(dataValue.substring(24, 28)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '4211', + type: 'AccelerometerY', + measurementValue: getSensorValue(dataValue.substring(28, 32)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '4212', + type: 'AccelerometerZ', + measurementValue: getSensorValue(dataValue.substring(32, 36)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '3000', + type: 'Battery', + measurementValue: getBattery(dataValue.substring(36, 38)) }) break } @@ -1389,6 +626,39 @@ function getMotionId (str) { } function getPositingStatus (str) { + let status = getInt(str) + switch (status) { + case 0: + return {id:status, statusName:"locate successful."} + case 1: + return {id:status, statusName:"The GNSS scan timed out."} + case 2: + return {id:status, statusName:"The Wi-Fi scan timed out."} + case 3: + return {id:status, statusName:"The Wi-Fi + GNSS scan timed out."} + case 4: + return {id:status, statusName:"The GNSS + Wi-Fi scan timed out."} + case 5: + return {id:status, statusName:"The Bluetooth scan timed out."} + case 6: + return {id:status, statusName:"The Bluetooth + Wi-Fi scan timed out."} + case 7: + return {id:status, statusName:"The Bluetooth + GNSS scan timed out."} + case 8: + return {id:status, statusName:"The Bluetooth + Wi-Fi + GNSS scan timed out."} + case 9: + return {id:status, statusName:"Location Server failed to parse the GNSS location."} + case 10: + return {id:status, statusName:"Location Server failed to parse the Wi-Fi location."} + case 11: + return {id:status, statusName:"Location Server failed to parse the Bluetooth location."} + case 12: + return {id:status, statusName:"Failed to parse location due to the poor accuracy."} + case 13: + return {id:status, statusName:"Time synchronization failed."} + case 14: + return {id:status, statusName:"Failed due to the old Almanac."} + } return getInt(str) } @@ -1526,7 +796,7 @@ function loraWANV2DataFormat (str, divisor = 1) { } }) str2 = parseInt(reverseArr.join(''), 2) + 1 - return '-' + str2 / divisor + return parseFloat('-' + str2 / divisor) } return parseInt(str2, 2) / divisor } @@ -1603,7 +873,6 @@ function getInt (str) { } function getEventStatus (str) { - // return getInt(str) let bitStr = getByteArray(str) let bitArr = [] for (let i = 0; i < bitStr.length; i++) { @@ -1676,7 +945,7 @@ function loraWANV2PositiveDataFormat (str, divisor = 1) {
-ChirpStack(V3)の場合 +ChirpStack(V3)向け ```cpp // Decode decodes an array of bytes into an object. @@ -2779,7 +2048,7 @@ function loraWANV2PositiveDataFormat(str) {
-AWS向け +AWS 向け ```cpp const AWS = require('aws-sdk'); @@ -3336,9 +2605,9 @@ exports.handler = async (event) => { ### SenseCAP T2000 トラッカー -#### デコーダー +#### デコーダ -[**SenseCAP T2000 トラッカー**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html)は、産業グレードのLoRaWAN®アセットトラッカーで、GNSS、Bluetooth、Wi-Fi測位をサポートし、屋内外環境での信頼性の高い追跡を実現します。IP67保護機能、動作状態を検出する内蔵3軸加速度計、デバイスが取り外された際に最優先アラームをトリガーする改ざん防止ボタンを備えています。T2000-AとT2000-Bは長時間のバッテリー動作をサポートし、充電式バッテリー付きソーラー電源のT2000-Cは継続的な屋外使用を保証し、このシリーズは長期間のメンテナンスフリーなアセット追跡に最適です。 +[**SenseCAP T2000 Tracker**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html) は、産業グレードの LoRaWAN® アセットトラッカーであり、GNSS、Bluetooth、Wi-Fi 位置情報をサポートし、屋内外の環境において信頼性の高いトラッキングを実現します。IP67 保護等級、動作状態を検知する内蔵 3 軸加速度センサ、取り外された場合に最優先アラームをトリガーするタンパー防止ボタンを備えています。T2000-A および T2000-B は長期間動作するバッテリ駆動をサポートし、充電式バッテリを備えたソーラ駆動の T2000-C は屋外での連続使用を可能にします。これにより、このシリーズは長期にわたるメンテナンスフリーのアセットトラッキングに最適です。

pir

@@ -3351,7 +2620,7 @@ exports.handler = async (event) => {
-TTN(ChirpStack V4)向け +TTN 用(ChirpStack V4) ```cpp function decodeUplink (input) { @@ -4063,7 +3332,7 @@ function loraWANV2PositiveDataFormat (str, divisor = 1) {
-Helium 向け +Helium 用 ```cpp function Decoder (bytes, port) { @@ -5527,11 +4796,11 @@ exports.handler = async (event) => { ```
-### Wio Tracker 1110 Dev Board +### Wio Tracker 1110 開発ボード -[Wio Tracker 1110 Dev Board](https://www.seeedstudio.com/Wio-Tracker-1110-Dev-Board-p-5799.html)は、[Wio-WM1110 Wireless Module](https://www.seeedstudio.com/Wio-WM1110-Module-LR1110-and-nRF52840-p-5676.html)をベースとし、[Semtech の LR1110](https://www.semtech.com/products/wireless-rf/lora-edge/lr1110) LoRa® トランシーバーと位置情報取得用の多目的無線フロントエンドを統合した、ユーザーフレンドリーな LoRa ベースのトラッキング開発プラットフォームです。 +[Wio Tracker 1110 Dev Board](https://www.seeedstudio.com/Wio-Tracker-1110-Dev-Board-p-5799.html) は、[Wio-WM1110 Wireless Module](https://www.seeedstudio.com/Wio-WM1110-Module-LR1110-and-nRF52840-p-5676.html) をベースとしており、[Semtech's LR1110](https://www.semtech.com/products/wireless-rf/lora-edge/lr1110) LoRa® トランシーバと測位用の多目的 RF フロントエンドを統合した、ユーザーフレンドリーな LoRa ベースのトラッキング開発プラットフォームです。 -コンパクトなサイズと豊富なインターフェースを備えた Wio Tracker 1110 Dev Board は、簡単な展開のためのオンボードアンテナを便利に装備しています。Arduino 開発環境と LoRaWAN プロトコルスタックをサポートし、トラッキング関連の IoT プロジェクトに最適です。 +コンパクトなサイズと豊富なインターフェースを備えた Wio Tracker 1110 Dev Board は、オンボードアンテナを搭載しており、容易に展開できます。Arduino 開発環境と LoRaWAN プロトコルスタックをサポートしているため、トラッキング関連の IoT プロジェクトに最適です。

pir

@@ -5541,11 +4810,11 @@ exports.handler = async (event) => {
-#### デコーダー +#### デコーダ
-TTN(ChirpStack V4)用 +TTN 用(ChirpStack V4) ```cpp function decodeUplink (input) { @@ -6149,7 +5418,7 @@ function loraWANV2PositiveDataFormat (str, divisor = 1) {
-Helium向け +Helium 向け ```cpp function Decoder (bytes, port) { @@ -6754,7 +6023,7 @@ function loraWANV2PositiveDataFormat (str, divisor = 1) {
-Chirp Stack 向け +Chirp Stack 用 ```cpp function Decode(fPort, bytes, variables) { @@ -7468,7 +6737,7 @@ function loraWANV2PositiveDataFormat(str) { ### SenseCAP S210X LoRaWAN センサー -[SenseCAP S210X](https://www.seeedstudio.com/catalogsearch/result/?q=s210x) は、ワイヤレス LoRaWAN® センサーのシリーズです。都市部では 2km、見通しの良い場所では 10km の伝送範囲をカバーしながら、伝送プロセス中の消費電力を低く抑えることができます。最大 10 年間の使用をサポートする交換可能なバッテリーと、産業用 IP66 エンクロージャーを備えています。-40 ~ 85℃ の動作温度をサポートし、過酷な環境でも展開できます。SenseCAP S210X は LoRaWAN® V1.0.3 プロトコルと互換性があり、LoRaWAN® ゲートウェイと連携できます。 +[SenseCAP S210X](https://www.seeedstudio.com/catalogsearch/result/?q=s210x) は、ワイヤレス LoRaWAN® センサーのシリーズです。都市環境では 2km、見通し線環境では 10km の伝送距離をカバーでき、伝送プロセス中の消費電力を低く抑えることができます。さらに、最大 10 年間の使用に対応する交換可能なバッテリーと、産業用 IP66 エンクロージャを備えています。-40 ~ 85℃ の動作温度をサポートし、過酷な環境にも展開できます。SenseCAP S210X は LoRaWAN® V1.0.3 プロトコルと互換性があり、LoRaWAN® ゲートウェイと連携して動作できます。

pir

@@ -7478,11 +6747,11 @@ function loraWANV2PositiveDataFormat(str) { -#### デコーダー +#### デコーダ
-TTN(ChirpStack V4)用 +TTN 用(ChirpStack V4) ```cpp /** @@ -9142,7 +8411,7 @@ exports.handler = async (event) => { ### SenseCAP S2100 データロガー -[SenseCAP S2100 データロガー](https://www.seeedstudio.com/SenseCAP-S2100-LoRaWAN-Data-Logger-p-5361.html)は、MODBUS-RTU RS485/アナログ/GPIOセンサーに接続でき、LoRaWANネットワークへのデータ送信を簡単に行える多機能デバイスです。LoRaとIP66設計により、このデバイスは優れた安定性と信頼性を誇り、超低消費電力を維持しながら長距離伝送をカバーできます。屋外使用に最適で、バッテリー駆動または12V外部電源接続により、さらなる柔軟性を提供します。12V電源に接続した場合、交換可能な内蔵バッテリーがバックアップ電源として機能します。さらに、S2100データロガーは内蔵Bluetoothを使用したOTAに最適化されており、セットアップとアップデートを迅速かつ簡単に行えます。さらに、S2110コンバーターによりS2100データロガーをGroveセンサーに接続できるため、DIY産業レベルLoRaWANセンサーや小規模展開に最適な選択肢となります。 +[SenseCAP S2100 Data Logger](https://www.seeedstudio.com/SenseCAP-S2100-LoRaWAN-Data-Logger-p-5361.html) は、多用途なデバイスで、MODBUS-RTU RS485/アナログ/GPIO センサーに接続でき、LoRaWAN ネットワークへのデータ送信を容易にします。LoRa と IP66 準拠の設計により、このデバイスは優れた安定性と信頼性を備え、超低消費電力を維持しながら長距離伝送を実現します。屋外での使用に最適で、バッテリー駆動に加えて、12V 外部電源に接続して使用することもでき、さらに高い柔軟性を提供します。12V 電源に接続されている場合、交換可能な内蔵バッテリーはバックアップ電源として機能します。さらに、S2100 データロガーは Bluetooth を内蔵し OTA に最適化されているため、セットアップやアップデートを素早く簡単に行えます。加えて、S2110 コンバータにより S2100 データロガーは Grove センサーに接続できるため、DIY の産業レベル LoRaWAN センサーや小規模な導入に最適な選択肢となります。
@@ -9152,9 +8421,9 @@ exports.handler = async (event) => { -#### デコーダー +#### デコーダ - + import Tabs2 from '@theme/Tabs'; import TabItem2 from '@theme/TabItem'; @@ -9164,7 +8433,7 @@ import TabItem2 from '@theme/TabItem';
-TTN(ChirpStack V4)向け +TTN 向け(ChirpStack V4) ```cpp /** @@ -9781,7 +9050,7 @@ function decodeUplink (input, port) {
- +
@@ -10403,9 +9672,9 @@ function bytes2HexString (arrBytes) { --- -### SenseCAP S2120 8-in-1 気象センサー +### SenseCAP S2120 8-in-1 Weather Sensor -[SenseCAP S2120 8-in-1 LoRaWAN 気象センサー](https://www.seeedstudio.com/sensecap-s2120-lorawan-8-in-1-weather-sensor-p-5436.html)は、気温、湿度、風速、風向、降雨量、光強度、UV指数、気圧を測定します。超低消費電力、信頼性の高い性能、内蔵Bluetooth、OTA設定とリモートデバイス管理のためのアプリサービスにより、低メンテナンスコストを実現します。裏庭、庭園、スマート農業、気象学、スマートシティなどのマルチシナリオアプリケーションをサポートします。 +[SenseCAP S2120 8-in-1 LoRaWAN Weather Sensor](https://www.seeedstudio.com/sensecap-s2120-lorawan-8-in-1-weather-sensor-p-5436.html) は、気温、湿度、風速、風向、降雨量、光強度、UV 指数、および気圧を測定します。超低消費電力、信頼性の高い性能、Bluetooth 内蔵、OTA 設定およびリモートデバイス管理用のアプリサービスにより、低い保守コストを実現します。裏庭、庭園、スマート農業、気象、スマートシティなど、複数のシナリオでのアプリケーションをサポートします。

pir

@@ -10415,7 +9684,7 @@ function bytes2HexString (arrBytes) { -#### デコーダー +#### デコーダ @@ -10423,11 +9692,11 @@ import Tabs3 from '@theme/Tabs'; import TabItem3 from '@theme/TabItem'; - +
-TTN(ChirpStack V4)向け +TTN 用(ChirpStack V4) ```cpp /** @@ -11508,9 +10777,9 @@ function Decoder (bytes, port) { --- -### SenseCAP A1101 - LoRaWAN Vision AI センサー +### SenseCAP A1101 - LoRaWAN Vision AI Sensor -[SenseCAP A1101 - LoRaWAN Vision AI センサー](https://www.seeedstudio.com/SenseCAP-A1101-LoRaWAN-Vision-AI-Sensor-p-5367.html)は、TinyML Edge AI対応のスマート画像センサーです。画像認識、人数カウント、ターゲット検出、メーター認識などの様々なAIモデルをサポートしています。また、TensorFlow Liteでのモデル訓練もサポートしています。 +[SenseCAP A1101 - LoRaWAN Vision AI Sensor](https://www.seeedstudio.com/SenseCAP-A1101-LoRaWAN-Vision-AI-Sensor-p-5367.html) は、TinyML エッジ AI を搭載したスマートイメージセンサです。画像認識、人数カウント、ターゲット検出、メーター認識など、さまざまな AI モデルをサポートします。また、TensorFlow Lite を使用したモデルのトレーニングにも対応しています。
@@ -11520,7 +10789,7 @@ function Decoder (bytes, port) { -#### デコーダー +#### デコーダ @@ -11528,11 +10797,11 @@ import Tabs4 from '@theme/Tabs'; import TabItem4 from '@theme/TabItem'; - +
-TTN向け(ChirpStack V4) +For TTN(ChirpStack V4) ```cpp /** @@ -11888,7 +11157,7 @@ function decodeUplink (input) {
- +
@@ -12568,19 +11837,19 @@ function toBinary (arr) { --- -### 使用方法 +### 使い方 ##### 準備 -デコーダーを設定する前に、製品マニュアルに従ってセンサーとゲートウェイを正しく設定し、必要なLoRaWANネットワークサーバーに接続してください。 +デコーダーを設定する前に、製品マニュアルに従ってセンサーとゲートウェイを正しくセットアップし、その後、必要な LoRaWAN ネットワークサーバーに接続してください。 -The Things Stackを例に、以下の手順に従ってデコーダーを設定してください: +ここでは The Things Stack を例として、以下の手順に従ってデコーダーを設定してください: ##### ペイロードデコーダーの設定 - デバイスの `Payload Formats` タブに移動します。 -- `Payload Format` で `Custom` を選択します -- `decoder.js` の全内容をコピーして `decoder` テキストエリアに貼り付けます。 +- `Payload Format` に `Custom` を選択します +- `decoder.js` の内容全体をコピーして、`decoder` テキストエリアに貼り付けます。 - `save payload functions` をクリックします

pir

@@ -12589,15 +11858,15 @@ The Things Stackを例に、以下の手順に従ってデコーダーを設定 まずサンプルペイロードでデコードスクリプトをテストすることができます。 -これを行うには、`01 01 10 98 53 00 00 01 02 10 A8 7A 00 00 AF 51` のような生データパケットを `Payload` テキスト入力にコピーし、デバイスマニュアルに従って `FPort` を選択してから、`Test` ボタンをクリックします。下に正常に解析されたJSON構造が表示されます。 +これを行うには、`01 01 10 98 53 00 00 01 02 10 A8 7A 00 00 AF 51` のような生データパケットを `Payload` テキスト入力欄にコピーし、デバイスマニュアルに従って `FPort` を選択し、`Test` ボタンをクリックします。すると、下に正常に解析された JSON 構造が表示されます。

pir

-次に、スクリプトの魔法を確認してみましょう。`Live Data` タブに移動すると、アップロードされたメッセージを展開してペイロード内の `Event Fields` を確認できます。これらのフィールドはスクリプトによって入力されたものです。 +それではスクリプトの魔法を確認してみましょう。`Live Data` タブに移動し、アップロードされた任意のメッセージを展開して、ペイロード内の `Event Fields` を確認できます。これらのフィールドはスクリプトによってちょうど埋め込まれたものです。

pir

-TTNのMQTT Data APIでメッセージを購読している場合、解析されたJSONペイロードフィールドも取得できます。 +もし TTN の MQTT Data API でメッセージを購読している場合も、解析済みの JSON ペイロードフィールドを取得できます。 ```cpp Client mosq-TCSlhYcKaRCn3cIePE received PUBLISH (d0, q0, r0, m0, 'lorawan868/devices/2cf7f12010700041/up', ... (719 bytes)) diff --git a/sites/ja/sidebars.js b/sites/ja/sidebars.js index 942944daf4c62..74959183f3053 100644 --- a/sites/ja/sidebars.js +++ b/sites/ja/sidebars.js @@ -714,6 +714,8 @@ const sidebars = { label: 'ユーザーガイド', items: [ 'Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/ja_Quick_Start', + 'Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/ja_Payload_Format', + 'Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/ja_FAQ', ], }, { diff --git a/sites/ja/static/js/language-switcher.js b/sites/ja/static/js/language-switcher.js index 050a1e1f64544..9c8bd3c479a06 100644 --- a/sites/ja/static/js/language-switcher.js +++ b/sites/ja/static/js/language-switcher.js @@ -1,6 +1,6 @@ // 语言切换器 - 生产环境优化版本 -// 生成时间: 2026-03-11 13:45:57 (北京时间) -// 多语言页面: 2207 个 +// 生成时间: 2026-03-12 17:40:12 (北京时间) +// 多语言页面: 2209 个 (function() { 'use strict'; @@ -13186,6 +13186,16 @@ "es", "ja" ], + "/t2000_faq": [ + "cn", + "es", + "ja" + ], + "/t2000_payload_format": [ + "cn", + "es", + "ja" + ], "/": [ "en", "cn", diff --git a/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/cn_FAQ.md b/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/cn_FAQ.md new file mode 100644 index 0000000000000..199ca7cb8b287 --- /dev/null +++ b/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/cn_FAQ.md @@ -0,0 +1,136 @@ +--- +description: SenseCAP T2000 Tracker 常见问题 +title: 常见问题 +keywords: + - Tracker + - SenseCAP +image: https://files.seeedstudio.com/wiki/SenseCAP/SenseCAP_T2000_Tracker/SenseCAP_T2000_Tracker_QuickStart.webp +slug: /t2000_faq +last_update: + date: 3/12/2026 + author: Janet +createdAt: '2026-03-12' +updatedAt: '2026-03-12' +url: https://wiki.seeedstudio.com/cn/t2000_faq/ +--- + +# 常见问题 + +### 定位相关 + +
+T2000 的典型 GNSS 定位精度是多少? + +- 在开阔天空环境下,T2000 的 GNSS 定位精度通常可达到米级精度。 +- 测试结果显示 CEP50(50% 圆概率误差)约为 **5–7 米**,这意味着超过一半的定位点会落在距离真实位置该范围内。 +- 实际定位精度可能会因环境、卫星可见度、安装条件等因素而有所不同。 + + +
+ + +
+为什么 GNSS 定位有时会出现漂移,或者没有 GNSS 经度和纬度数据? + +- GNSS 精度会受到多种环境因素的影响: + - 建筑物、树木或其他障碍物阻挡卫星信号。 + - 由墙体或金属表面反射信号引起的多径效应。 + - 附近电子设备产生的电磁干扰。 + - 天线朝向不佳或安装位置不合理。 + +- 在某些情况下,设备可能不会上报 GNSS 经度和纬度数据,是因为 GNSS 扫描已超时。该状态可以在上行载荷中看到,此时 **定位状态** 字段会显示 **"GNSS scan timeout"**,原因与上述相同的环境条件有关。 + +- 为获得最佳效果,请将设备安装在户外开阔区域,并确保有良好的天空视野。 + +
+ + +
+如何安装 T2000 才能获得最佳 GNSS 性能? + +- 将设备放置在开阔环境中,尽量减少对卫星信号的遮挡。 +- 确保 GNSS 天线区域朝上,面向天空。 +- 避免将设备安装在大型金属物体或密集结构附近。 +- 避免覆盖设备或将其放置在封闭的金属外壳内。 +![Antenna](https://files.seeedstudio.com/wiki/SenseCAP/SenseCAP_T2000_Tracker/T2000-antenna.png) + +
+ +
+为什么 Wi-Fi 或蓝牙定位没有显示在 SenseCraft App 地图上? + +- Wi-Fi 和蓝牙定位需要调用第三方地图解析服务进行解析,目前 SenseCraft App 仅支持 GNSS 定位显示。 + +
+ +
+ +有关 GNSS 定位的更多详情,请参考博客:[SenseCAP T2000 GNSS 定位有多精确?](https://www.seeedstudio.com/blog/2026/01/19/how-accurate-is-the-sensecap-t2000-gnss-positioning/) + + +### 电池相关 + +
+T2000-A/B 与 T2000-C 的电池有什么区别? + +- **T2000-A/B** + - 由 **8000mAh 一次性电池**供电。 + - 适用于无需充电的长期部署场景。 + +- **T2000-C** + - 由 **4000mAh 可充电电池**供电。 + - 配备 **0.5W 太阳能板**,支持持续户外运行。 + - 适用于有日照、且需要尽量减少维护的部署场景。 + +
+ + +
+T2000-C 的太阳能充电效率如何? + +- T2000-C 使用 **0.5W 太阳能板配合可充电电池**,以支持长期户外运行。 +- 在良好日照条件下,太阳能板最高可产生约 **60mA 的充电电流**,每小时大约产生 **60mAh** 的电量(该数据仅供参考)。 + +
+ + +
+哪些因素会影响太阳能充电效率? + +- 太阳能充电性能可能会因以下因素而变化: + - 日照时间和光照强度 + - 太阳能板的朝向和安装角度 + - 周围物体造成的遮挡 + - 太阳能板表面的灰尘、污垢或杂物 + - 环境温度(电池充电工作温度为 0–45°C) + +- 为获得最佳性能,请将设备安装在有直射阳光的位置,并定期检查太阳能板表面。 + +
+ + +
+T2000-C 能否依靠太阳能持续运行? + +- 在低功耗配置(例如较长的上行间隔)下,太阳能充电甚至可以在日常运行中维持或提升电池电量。 +- 但是,如果上报间隔非常频繁(例如每 1 分钟一次),其耗电量可能会超过太阳能板所能补充的电量。 +- 如需更详细的太阳能充电性能分析,请参考以下博客:[SenseCAP T2000‑C 的太阳能充电效率如何?](https://www.seeedstudio.com/blog/2026/01/19/how-efficient-is-the-solar-charging-on-the-sensecap-t2000-c/) + +
+ +您可以使用以下 [电池寿命计算器](https://files.seeedstudio.com/products/SenseCAP/T2000_Tracker/SenseCAP_Tracker_Battery_Life_Calculator_T2000.xls) 来估算电池寿命。 + + +## 技术支持与产品讨论 + +感谢您选择我们的产品!我们将为您提供多种支持,确保您在使用我们产品的过程中尽可能顺畅。我们提供多种沟通渠道,以满足不同的偏好和需求。 + +
+ + +
+ +
+ + +
\ No newline at end of file diff --git a/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/cn_Payload_Format.md b/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/cn_Payload_Format.md new file mode 100644 index 0000000000000..7bd7bc729356c --- /dev/null +++ b/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/cn_Payload_Format.md @@ -0,0 +1,522 @@ +--- +description: SenseCAP T2000 Tracker 负载格式 +title: 负载格式 +keywords: + - Tracker + - SenseCAP +image: https://files.seeedstudio.com/wiki/SenseCAP/SenseCAP_T2000_Tracker/SenseCAP_T2000_Tracker_QuickStart.webp +slug: /t2000_payload_format +last_update: + date: 3/12/2026 + author: Janet +createdAt: '2026-03-12' +updatedAt: '2026-03-12' +url: https://wiki.seeedstudio.com/cn/t2000_payload_format/ +--- + +# 负载格式 + +## 上行数据包解析 + +追踪器数据协议提供了不同的数据包来对应不同的信息,每个数据包的字节数可能不同。帧结构如下图所示。帧内容以**大端字节序**发送。 + +|数据 ID|数据值| +| - | :- | +|1 字节|50 字节(最大)| + +**Data ID**: 功能编号。
+**Data Value**: 位置、传感器数据和其他信息。 + +### 上电数据包 (0x27) + +上电数据包由设备在启动后立即发送。它包含当前的配置参数和设备状态。帧 ID 为 `0x27`,总长度为 46 字节。 + +| 0x27 | Byte2 | Byte3~4 | Byte5~6 | Byte7 | Byte8 | Byte9~10 | Byte11~12 | +| :--: | :---: | :-----: | :-----: | :--: | :--: | :------: | :-------: | +| ID | 电池电量 | 软件版本 | 硬件版本 | 工作模式 | 定位策略 | 心跳间隔 | 周期模式上行间隔 | + +| Byte13~14 | Byte15 | Byte16 | Byte17 | Byte18 | Byte19~20 | Byte21~22 | +| :-------: | :----: | :----: | :----: | :----: | :-------: | :-------: | +| 事件模式上行间隔 | 使能三轴加速度计 | 使能拆卸告警 | GNSS 扫描超时 | 使能运动事件 | 三轴运动阈值 | 运动时上行间隔 | + +| Byte23 | Byte24~25 | Byte26 | Byte27~28 | Byte29 | Byte30 | Byte31~46 | +| :----: | :-------: | :----: | :-------: | :----: | :----: | :-------: | +| 使能静止事件 | 静止超时 | 使能震动事件 | 三轴震动阈值 | iBeacon 扫描超时 (s) | UUID 过滤有效字节数 | UUID 过滤器 (16 字节) | + +**原始负载示例** + +`27 56 0100 0101 01 08 02d0 003c 003c 00 01 3c 00 001e 0005 00 0168 00 012c 03 00 00000000000000000000000000000000` + +| 字节 | 字段 | 类型 | 原始数据 | 说明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 27 | 27 为数据包 ID | +| 2 | 电池电量 | uint8 | 56 | `0x56` = 86(DEC)
电池电量为 86% | +| 3~4 | 软件版本 | uint16 | 0100 | `0x0100` = v1.0
软件版本为 v1.0 | +| 5~6 | 硬件版本 | uint16 | 0101 | `0x0101` = v1.1
硬件版本为 v1.1 | +| 7 | 工作模式 | uint8 | 01 | 01 = 周期模式
`00`: 待机模式
`01`: 周期模式
`02`: 事件模式 | +| 8 | 定位策略 | uint8 | 00 | 07 = 0x07,表示设备使用 Bluetooth + Wi-Fi + GNSS 定位策略
`00`: 仅 GNSS
`01`: 仅 Wi-Fi
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: 仅 Bluetooth
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +| 9~10 | 心跳间隔 | uint16 | 02d0 | `0x02D0` = 720 分钟 | +| 11~12 | 周期模式上行间隔 | uint16 | 003c | `0x003C` = 60 分钟 | +| 13~14 | 事件模式上行间隔 | uint16 | 003c | `0x003C` = 60 分钟 | +| 15 | 使能三轴加速度计 | uint8 | 00 | `00`: 禁用
`01`: 使能 | +| 16 | 使能拆卸告警 | uint8 | 01 | `00`: 禁用
`01`: 使能 | +| 17 | GNSS 扫描超时 | uint8 | 3c | `0x3C` = 60 秒 | +| 18 | 使能运动事件 | uint8 | 00 | `00`: 禁用
`01`: 使能 | +| 19~20 | 三轴运动阈值 | uint16 | 001e | `0x001e` = 30 mg | +| 21~22 | 运动时上行间隔 | uint16 | 0005 | `0x05` = 5 分钟 | +| 23 | 使能静止事件 | uint8 | 00 | `0x00`: 禁用
`0x01`: 使能 | +| 24~25 | 静止超时 | uint16 | 0168 | `0x0168` = 360 分钟 | +| 26 | 使能震动事件 | uint8 | 00 | `00`: 禁用
`01`: 使能 | +| 27~28 | 三轴震动阈值 | uint16 | 012c | `0x012c` = 300 mg | +| 29 | iBeacon 扫描超时 (s) | uint8 | 03 | `0x03` = 3 秒 | +| 30 | UUID 过滤有效字节数 | uint8 | 00 | UUID 过滤器中有效字节的数量 (0–16) | +| 31~46 | UUID 过滤器 | 16 bytes | 0000000000000000
0000000000000000 | 16 字节 Bluetooth UUID 过滤器。只有前 N 个字节(由 byte30 定义)有效 | + +### 周期模式数据包 (0x28) + +周期模式参数数据包包含当前工作模式的配置。帧 ID 为 `0x28`,总长度为 30 字节。 + +| 0x28 | Byte2 | Byte3 | Byte4~5 | Byte6~7 | Byte8~9 | Byte10 | Byte11 | Byte12 | Byte13 | Byte14 | Byte15~30 | +| :--: | :---: | :---: | :-----: | :-----: | :-----: | :----: | :----: | :----: | :----: | :----: | :-------: | +| ID | 工作模式 | 定位策略 | 心跳间隔 | 上行间隔 | 事件模式上行间隔 | 使能三轴加速度计 | 使能拆卸告警 | GNSS 扫描超时 | iBeacon 扫描超时 | UUID 过滤有效字节数 | UUID 过滤器 (16 字节) | + +**原始负载示例** + +`28 01 07 02d0 003c 003c 01 00 3c 0a 10 00000000000000000000000000000000` + +| 字节 | 字段 | 类型 | 原始数据 | 说明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 28 | 28 为数据包 ID | +| 2 | 工作模式 | uint8 | 01 | 01 = 周期模式
`00`: 待机模式
`01`: 周期模式
`02`: 事件模式 | +| 3 | 定位策略 | uint8 | 07 | 07 = 0x07,表示设备使用 Bluetooth + Wi-Fi + GNSS 定位策略
`00`: 仅 GNSS
`01`: 仅 Wi-Fi
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: 仅 Bluetooth
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +| 4~5 | 心跳间隔 | uint16 | 02d0 | `0x02D0` = 720 分钟 | +| 6~7 | 上行间隔 | uint16 | 003c | `0x003C` = 60 分钟 | +| 8~9 | 事件模式上行间隔 | uint16 | 003c | `0x003C` = 60 分钟
当没有事件触发时,将每 60 分钟上传一次数据。
| +| 10 | 使能三轴加速度计 | uint8 | 01 | `00`: 禁用
`01`: 使能 | +| 11 | 使能拆卸告警 | uint8 | 00 | `00`: 禁用
`01`: 使能 | +| 12 | GNSS 扫描超时 | uint8 | 3c | `0x3C` = 60 秒 | +| 13 | iBeacon 扫描超时 | uint8 | 0a | `0x0A` = 10 秒 | +| 14 | UUID 过滤有效字节数 | uint8 | 10 | UUID 过滤器中有效字节的数量 (0–16) | +| 15~30 | UUID 过滤器 | 16 bytes | 0000000000000000
0000000000000000 | 16 字节 Bluetooth UUID 过滤器。只有前 N 个字节(由 byte14 定义)有效 | + +### 事件模式数据包 (0x29) + +事件参数数据包包含运动、静止和震动事件的配置设置。帧 ID 为 `0x29`,总长度为 12 字节。 + +| 0x29 | Byte2 | Byte3~4 | Byte5~6 | Byte7 | Byte8~9 | Byte10 | Byte11~12 | +| :--: | :---: | :-----: | :-----: | :--: | :-----: | :----: | :-------: | +| ID | 使能运动事件 | 三轴运动阈值 | 运动时上行间隔 | 使能静止事件 | 静止超时 | 使能震动事件 | 三轴震动阈值 | + +**原始负载示例** + +`29 01 0064 001e 01 012c 00 012c` + +| 字节 | 字段 | 类型 | 原始数据 | 说明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 29 | 29 为数据包 ID | +| 2 | 使能运动事件 | uint8 | 01 | `00`: 禁用
`01`: 使能 | +| 3~4 | 三轴运动阈值 | uint16 | 0064 | `0x0064` = 100 mg | +| 5~6 | 运动时上行间隔 | uint16 | 001e | `0x001E` = 30 分钟 | +| 7 | 使能静止事件 | uint8 | 01 | `0x00`: 禁用
`0x01`: 使能 | +| 8~9 | 静止超时 | uint16 | 012c | `0x012C` = 300 分钟 | +| 10 | 使能震动事件 | uint8 | 00 | `0x00`: 禁用
`0x01`: 使能 | +| 11~12 | 三轴震动阈值 | uint16 | 0000 | `0x012c` = 300 mg | + +### 心跳数据包 (0x2A) + +心跳数据包由设备周期性发送,用于上报当前状态。它包含基本的设备信息和传感器状态。帧 ID 为 `0x2A`,总长度为 6 字节。 + +| 0x2A | Byte2 | Byte3 | Byte4 | Byte5 | Byte6 | +| :--: | :---: | :---: | :---: | :---: | :---: | +| ID | 电池电量 | 工作模式 | 定位策略 | 使能三轴加速度计 | 使能拆卸告警 | + +**原始负载示例** + +`2a 56 01 07 01 00` + +| 字节 | 字段 | 类型 | 原始数据 | 说明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 2A | 2A 为数据包 ID | +| 2 | 电池电量 | uint8 | 56 | `0x56` = 86(DEC)
电池电量为 86% | +| 3 | 工作模式 | uint8 | 01 | 01 = 周期模式
`00`: 待机模式
`01`: 周期模式
`02`: 事件模式 | +| 4 | 定位策略 | uint8 | 07 | 07 = 0x07,表示设备使用 Bluetooth + Wi-Fi + GNSS 定位策略
`00`: 仅 GNSS
`01`: 仅 Wi-Fi
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: 仅 Bluetooth
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +| 5 | 使能三轴加速度计 | uint8 | 01 | `00`: 禁用
`01`: 使能 | +| 6 | 使能拆卸告警 | uint8 | 00 | `00`: 禁用
`01`: 使能 | + +### GNSS 位置数据包(加速度计开启,0x2B) + +GPS 位置数据包包含 GNSS 定位数据以及加速度计和电池信息。帧 ID 为 `0x2B`,总长度为 23 字节。 + +| 0x2B | Byte2~3 | Byte4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15~18 | Byte19~22 | Byte23 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :-------: | :------: | :------: | :---: | +| ID | 事件状态 | 运动 ID | UTC 时间戳 | 加速度计 X | 加速度计 Y | 加速度计 Z | 经度 | 纬度 | 电池电量 | + +**原始负载示例** + +`2b 0100 00 694b3dc6 032f fffe 0241 06ca5098 01587ee4 62` + +| 字节 | 字段 | 类型 | 原始数据 | 说明 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 2B | 2B 为数据包 ID | +| 2~3 | 事件状态 | uint16 | 0100 | `0x0100` = 拆卸事件
位 0: false
位 1: 开始运动事件
位 2: 结束运动事件
位 3: 静止事件
位 4: 震动事件
位 5: 温度事件
位 6: 光照事件
位 7: SOS 事件
位 8: 单击事件
位 9: 拆卸事件

转换为十六进制:
`0x0001`: 开始运动事件
`0x0002`: 结束运动事件
`0x0004`: 静止事件
`0x0008`: 震动事件
`0x0010`: 温度事件
`0x0020`: 光照事件
`0x0040`: SOS 事件
`0x0080`: 单击事件
`0x0100`: 拆卸事件 | +| 4 | 运动 ID | uint8 | 00 | `0`: 不需要记录为特定运动。
`1~255`: 在相同运动状态下上报的定位数据(相同 ID 表示同一次运动) | +| 5~8 | UTC 时间戳 | uint32 | 694b3dc6 | `0x694B3DC6` = 1766538694(DEC) 秒

转换为 UTC 时间:
2025-12-24 01:11:34 | +| 9~10 | 加速度计 X | int16 | 032f | `0x032F` = 815 mg | +| 11~12 | 加速度计 Y | int16 | fffe | `0xFFFE` = -2 mg | +| 13~14 | 加速度计 Z | int16 | 0241 | `0x0241` = 577 mg | +| 15~18 | 经度 | uint32 | 06ca5098 | `0x06CA5098` = 113,922,200 → 113.922200° | +| 19~22 | 纬度 | uint32 | 01587ee4 | `0x01587EE4` = 22,576,868 → 22.576868° | +| 23 | 电池电量 | uint8 | 62 | `0x62` = 98% | + +### Wi-Fi 定位数据包(加速度计开启,0x2C) + +Wi-Fi 定位数据包包含 Wi-Fi 扫描结果以及加速度计和电池信息。帧 ID 为 `0x2C`,总长度会根据扫描到的 Wi-Fi 接入点数量动态变化(23 + (n-1) * 7 字节,其中 n 为 MAC-RSSI 对的数量)。 + +| 0x2C | Byte2~3 | Byte4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15 | Byte16 | Byte17+(n-1)*7 ~ Byte23+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :-------: | :---: | :---: | :---------------------------: | +| ID | 事件状态 | 运动 ID | UTC 时间戳 | 加速度计 X | 加速度计 Y | 加速度计 Z | 电池电量 | MAC-RSSI 计数 (n) | MAC-RSSI 对 (n) | + +**MAC-RSSI 格式** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| MAC 地址(6 字节) | RSSI (int8) | + +**原始载荷示例** + +`2c 0000 00 69685f82 0004 0015 03e5 64 05 107c61841bf8 e4 3447d468f627 e1 a4ba70bc229d d3 9483c46d5dfc d2 4c10d567b467 d0` + +| Byte | 值 | 类型 | 原始数据 | 描述 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 2C | 2C 是数据包 ID | +| 2~3 | 事件状态 | uint16 | 0000 |`0x0000` = 未触发任何事件
Bit 0: false
Bit 1: 开始移动事件
Bit 2: 结束移动事件
Bit 3: 静止事件
Bit 4: 震动事件
Bit 5: 温度事件
Bit 6: 光照事件
Bit 7: SOS 事件
Bit 8: 单击事件
Bit 9: 拆卸事件

转换为十六进制:
`0x0001`: 开始移动事件
`0x0002`: 结束移动事件
`0x0004`: 静止事件
`0x0008`: 震动事件
`0x0010`: 温度事件
`0x0020`: 光照事件
`0x0040`: SOS 事件
`0x0080`: 单击事件
`0x0100`: 拆卸事件| +| 4 | 运动 ID | uint8 | 00 | `0`: 不需要记录为特定运动。
`1~255`: 在相同运动状态下上报的定位数据(相同 ID 表示相同运动) | +| 5~8 | UTC 时间戳 | uint32 | 69685f82 | `0x69685F82` = 1768447874(DEC) 秒

转换为 UTC 时间:
2026-01-15 03:31:14 | +| 9~10 | 加速度计 X | int16 | 0004 | `0x0004` = 4 mg | +| 11~12 | 加速度计 Y | int16 | 0015 | `0x0015` = 21 mg | +| 13~14 | 加速度计 Z | int16 | 03e5 | `0x03E5` = 997 mg | +| 15 | 电池电量 | uint8 | 64 | `0x64` = 100% | +| 16 | MAC-RSSI 计数 (n) | uint8 | 05 | 检测到的 Wi-Fi 接入点数量(n = 5) | +| 17~23 | MAC-RSSI 对 1 | 7 bytes | 107c61841bf8 e4 | MAC: `10:7C:61:84:1B:F8`, RSSI: `0xE4` = -28 (int8) | +| 24~30 | MAC-RSSI 对 2 | 7 bytes | 3447d468f627 e1 | MAC: `34:47:D4:68:F6:27`, RSSI: `0xE1` = -31 (int8) | +| 31~37 | MAC-RSSI 对 3 | 7 bytes | a4ba70bc229d d3 | MAC: `A4:BA:70:BC:22:9D`, RSSI: `0xD3` = -45 (int8) | +| 38~44 | MAC-RSSI 对 4 | 7 bytes | 9483c46d5dfc d2 | MAC: `94:83:C4:6D:5D:FC`, RSSI: `0xD2` = -46 (int8) | +| 45~51 | MAC-RSSI 对 5 | 7 bytes | 4c10d567b467 d0 | MAC: `4C:10:D5:67:B4:67`, RSSI: `0xD0` = -48 (int8) | + +### BLE 定位数据包(加速度计开启,0x2D) + +BLE 定位数据包包含蓝牙扫描结果以及加速度计和电池信息。帧 ID 为 `0x2D`,总长度会根据扫描到的蓝牙设备数量动态变化(23 + (n-1) * 7 字节,其中 n 为 MAC-RSSI 对的数量,最大 n = 5)。 + +| 0x2D | Byte2~3 | Byte4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15 | Byte16 | Byte17+(n-1)*7 ~ Byte23+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :-------: | :---: | :---: | :---------------------------: | +| ID | 事件状态 | 运动 ID | UTC 时间戳 | 加速度计 X | 加速度计 Y | 加速度计 Z | 电池电量 | MAC-RSSI 计数 (n) | MAC-RSSI 对 (n) | + +**MAC-RSSI 格式** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| MAC 地址(6 字节) | RSSI (int8) | + +**原始载荷示例** + +`2d 0000 00 69686032 fff9 0015 03df 64 05 c30000564b3b ce c20303003f00 ce 588c81a0fbf2 cc c20303003f03 cb c30000564af2 c7` + +| Byte | 值 | 类型 | 原始数据 | 描述 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 2D | 2D 是数据包 ID | +| 2~3 | 事件状态 | uint16 | 0000 |`0x0000` = 未触发任何事件
Bit 0: false
Bit 1: 开始移动事件
Bit 2: 结束移动事件
Bit 3: 静止事件
Bit 4: 震动事件
Bit 5: 温度事件
Bit 6: 光照事件
Bit 7: SOS 事件
Bit 8: 单击事件
Bit 9: 拆卸事件

转换为十六进制:
`0x0001`: 开始移动事件
`0x0002`: 结束移动事件
`0x0004`: 静止事件
`0x0008`: 震动事件
`0x0010`: 温度事件
`0x0020`: 光照事件
`0x0040`: SOS 事件
`0x0080`: 单击事件
`0x0100`: 拆卸事件| +| 4 | 运动 ID | uint8 | 00 | `0`: 不需要记录为特定运动。
`1~255`: 在相同运动状态下上报的定位数据(相同 ID 表示相同运动) | +| 5~8 | UTC 时间戳 | uint32 | 69686032 | `0x69686032` = 1768448050(DEC) 秒

转换为 UTC 时间:
2026-01-15 03:34:10 | +| 9~10 | 加速度计 X | int16 | fff9 | `0xFFF9` = -7 mg | +| 11~12 | 加速度计 Y | int16 | 0015 | `0x0015` = 21 mg | +| 13~14 | 加速度计 Z | int16 | 03df | `0x03DF` = 991 mg | +| 15 | 电池电量 | uint8 | 64 | `0x64` = 100% | +| 16 | MAC-RSSI 计数 (n) | uint8 | 05 | 检测到的蓝牙设备数量(n = 5,最大 5) | +| 17~23 | MAC-RSSI 对 1 | 7 bytes | c30000564b3b ce | MAC: `C3:00:00:56:4B:3B`, RSSI: `0xCE` = -50 (int8) | +| 24~30 | MAC-RSSI 对 2 | 7 bytes | c20303003f00 ce | MAC: `C2:03:03:00:3F:00`, RSSI: `0xCE` = -50 (int8) | +| 31~37 | MAC-RSSI 对 3 | 7 bytes | 588c81a0fbf2 cc | MAC: `58:8C:81:A0:FB:F2`, RSSI: `0xCC` = -52 (int8) | +| 38~44 | MAC-RSSI 对 4 | 7 bytes | c20303003f03 cb | MAC: `C2:03:03:00:3F:03`, RSSI: `0xCB` = -53 (int8) | +| 45~51 | MAC-RSSI 对 5 | 7 bytes | c30000564af2 c7 | MAC: `C3:00:00:56:4A:F2`, RSSI: `0xC7` = -57 (int8) | + +### GNSS 定位数据包(加速度计关闭,0x2E) + +GNSS 定位数据包包含 GPS 定位数据以及电池信息。帧 ID 为 `0x2E`,总长度为 17 字节。 + +| 0x2E | Byte2~3 | Byte4 | Byte5~8 | Byte9~12 | Byte13~16 | Byte17 | +| :--: | :-----: | :--: | :-----: | :------: | :-------: | :----: | +| ID | 事件状态 | 运动 ID | UTC 时间戳 | 经度 | 纬度 | 电池电量 | + +**原始载荷示例** + +`2e 0100 01 64f1a2b3 06ca5098 01587ee4 62` + +| Byte | 值 | 类型 | 原始数据 | 描述 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 2E | 2E 是数据包 ID | +| 2~3 | 事件状态 | uint16 | 0000 |`0x0000` = 未触发任何事件
Bit 0: false
Bit 1: 开始移动事件
Bit 2: 结束移动事件
Bit 3: 静止事件
Bit 4: 震动事件
Bit 5: 温度事件
Bit 6: 光照事件
Bit 7: SOS 事件
Bit 8: 单击事件
Bit 9: 拆卸事件

转换为十六进制:
`0x0001`: 开始移动事件
`0x0002`: 结束移动事件
`0x0004`: 静止事件
`0x0008`: 震动事件
`0x0010`: 温度事件
`0x0020`: 光照事件
`0x0040`: SOS 事件
`0x0080`: 单击事件
`0x0100`: 拆卸事件| +| 4 | 运动 ID | uint8 | 00 | `0`: 不需要记录为特定运动。
`1~255`: 在相同运动状态下上报的定位数据(相同 ID 表示相同运动) | +| 5~8 | UTC 时间戳 | uint32 | 64f1a2b3 | `0x64f1a2b3` = 1693557427(DEC) 秒

转换为 UTC 时间:
2023-09-01 08:37:07 | +| 9~12 | 经度 | uint32 | 06ca5098 | `0x06CA5098` = 113,922,200 → 113.922200° | +| 13~16 | 纬度 | uint32 | 01587ee4 | `0x01587EE4` = 22,576,868 → 22.576868° | +| 17 | 电池电量 | uint8 | 62 | `0x62` = 98% | + +### Wi-Fi 定位数据包(加速度计关闭,0x2F) + +Wi-Fi 定位数据包包含 Wi-Fi 扫描结果以及电池信息。帧 ID 为 `0x2F`,总长度会根据扫描到的 Wi-Fi 接入点数量动态变化(17 + (n-1) * 7 字节,其中 n 为 MAC-RSSI 对的数量,最大 n = 5)。 + +| 0x2F | Byte2~3 | Byte4 | Byte5~8 | Byte9 | Byte10 | Byte11+(n-1)*7 ~ Byte16+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :---: | :----: | :---------------------------: | +| ID | 事件状态 | 运动 ID | UTC 时间戳 | 电池电量 | MAC-RSSI 计数 (n) | MAC-RSSI 对 (n) | + +**MAC-RSSI 格式** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| MAC 地址(6 字节) | RSSI (int8) | + +**原始载荷示例** + +`2f 0000 00 69685f82 64 05 107c61841bf8 e4 3447d468f627 e1 a4ba70bc229d d3 9483c46d5dfc d2 4c10d567b467 d0` + +| Byte | 值 | 类型 | 原始数据 | 描述 | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 2F | 2F 是数据包 ID | +| 2~3 | 事件状态 | uint16 | 0000 |`0x0000` = 未触发任何事件
Bit 0: false
Bit 1: 开始移动事件
Bit 2: 结束移动事件
Bit 3: 静止事件
Bit 4: 震动事件
Bit 5: 温度事件
Bit 6: 光照事件
Bit 7: SOS 事件
Bit 8: 单击事件
Bit 9: 拆卸事件

转换为十六进制:
`0x0001`: 开始移动事件
`0x0002`: 结束移动事件
`0x0004`: 静止事件
`0x0008`: 震动事件
`0x0010`: 温度事件
`0x0020`: 光照事件
`0x0040`: SOS 事件
`0x0080`: 单击事件
`0x0100`: 拆卸事件| +| 4 | 运动 ID | uint8 | 00 | `0`: 不需要记录为特定运动。
`1~255`: 在相同运动状态下上报的定位数据(相同 ID 表示相同运动) | +| 5~8 | UTC 时间戳 | uint32 | 69685f82 | `0x69685F82` = 1768447874(DEC) 秒

转换为 UTC 时间:
2026-01-15 03:31:14 | +| 9 | 电池电量 | uint8 | 64 | `0x64` = 100% | +| 10 | MAC-RSSI 计数 (n) | uint8 | 05 | 检测到的 Wi-Fi 接入点数量(n = 5,最大 5) | +| 11~17 | MAC-RSSI 对 1 | 7 bytes | 107c61841bf8 e4 | MAC: `10:7C:61:84:1B:F8`,
RSSI: `0xE4` = -28 (int8) | +| 18~24 | MAC-RSSI 对 2 | 7 bytes | 3447d468f627 e1 | MAC: `34:47:D4:68:F6:27`,
RSSI: `0xE1` = -31 (int8) | +| 25~31 | MAC-RSSI 对 3 | 7 bytes | a4ba70bc229d d3 | MAC: `A4:BA:70:BC:22:9D`,
RSSI: `0xD3` = -45 (int8) | +| 32~38 | MAC-RSSI 对 4 | 7 bytes | 9483c46d5dfc d2 | MAC: `94:83:C4:6D:5D:FC`,
RSSI: `0xD2` = -46 (int8) | +| 39~45 | MAC-RSSI 对 5 | 7 bytes | 4c10d567b467 d0 | MAC: `4C:10:D5:67:B4:67`,
RSSI: `0xD0` = -48 (int8) | + +### BLE 定位数据包(加速度计关闭,0x30) + +BLE 定位数据包包含蓝牙扫描结果以及电池信息。帧 ID 为 `0x30`,总长度会根据扫描到的蓝牙设备数量动态变化(17 + (n-1) * 7 字节,其中 n 为 MAC-RSSI 对的数量,最大 n = 5)。 + +| 0x30 | Byte2~3 | Byte4 | Byte5~8 | Byte9 | Byte10 | Byte11+(n-1)*7 ~ Byte16+(n-1)*7 | +| :--: | :-----: | :--: | :-----: | :---: | :----: | :---------------------------: | +| ID | 事件状态 | 运动 ID | UTC 时间戳 | 电池电量 | MAC-RSSI 计数 (n) | MAC-RSSI 对 (n) | + +**MAC-RSSI 格式** + +| Byte0~5 | Byte6 | +| :-----: | :---: | +| MAC 地址(6 字节) | RSSI (int8) | + +**原始载荷示例** + +`30 0000 00 69686032 64 05 c30000564b3b ce c20303003f00 ce 588c81a0fbf2 cc c20303003f03 cb c30000564af2 c7` + +| Byte | Value | Type | Raw Data | Description | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 30 | 30 是数据包 ID | +| 2~3 | 事件状态 | uint16 | 0000 |`0x0000` = 未触发任何事件
Bit 0: false
Bit 1: 开始移动事件
Bit 2: 结束移动事件
Bit 3: 静止事件
Bit 4: 震动事件
Bit 5: 温度事件
Bit 6: 光照事件
Bit 7: SOS 事件
Bit 8: 单击事件
Bit 9: 拆卸事件

转换为十六进制:
`0x0001`: 开始移动事件
`0x0002`: 结束移动事件
`0x0004`: 静止事件
`0x0008`: 震动事件
`0x0010`: 温度事件
`0x0020`: 光照事件
`0x0040`: SOS 事件
`0x0080`: 单击事件
`0x0100`: 拆卸事件| +| 4 | 运动 ID | uint8 | 00 | `0`: 不需要记录为特定运动。
`1~255`: 在相同运动状态下上报的定位数据(相同 ID 表示相同运动) | +| 5~8 | UTC 时间戳 | uint32 | 69686032 | `0x69686032` = 1768448050(DEC) 秒

转换为 UTC 时间:
2026-01-15 03:34:10 | +| 9 | 电池电量 | uint8 | 64 | `0x64` = 100% | +| 10 | MAC-RSSI 计数 (n) | uint8 | 05 | 检测到的蓝牙设备数量(n = 5,最大 5) | +| 11~17 | MAC-RSSI 对 1 | 7 bytes | c30000564b3b ce | MAC: `C3:00:00:56:4B:3B`,
RSSI: `0xCE` = -50 (int8) | +| 18~24 | MAC-RSSI 对 2 | 7 bytes | c20303003f00 ce | MAC: `C2:03:03:00:3F:00`,
RSSI: `0xCE` = -50 (int8) | +| 25~31 | MAC-RSSI 对 3 | 7 bytes | 588c81a0fbf2 cc | MAC: `58:8C:81:A0:FB:F2`,
RSSI: `0xCC` = -52 (int8) | +| 32~38 | MAC-RSSI 对 4 | 7 bytes | c20303003f03 cb | MAC: `C2:03:03:00:3F:03`,
RSSI: `0xCB` = -53 (int8) | +| 39~45 | MAC-RSSI 对 5 | 7 bytes | c30000564af2 c7 | MAC: `C3:00:00:56:4A:F2`,
RSSI: `0xC7` = -57 (int8) | + +### 带加速度计的定位状态数据包 (0x31) + +定位状态数据包包含定位状态以及加速度计数据、事件状态和电池信息。帧 ID 为 `0x31`,总长度为 15 字节。 + +| 0x31 | Byte2 | Byte3~4 | Byte5~8 | Byte9~10 | Byte11~12 | Byte13~14 | Byte15 | +| :--: | :---: | :-----: | :-----: | :------: | :-------: | :-------: | :---: | +| ID | 定位状态 | 事件状态 | UTC 时间戳 | 加速度计 X | 加速度计 Y | 加速度计 Z | 电池电量 | + +**原始载荷示例** + +`31 00 0100 694b3db0 003a 039d fe84 62` + +| Byte | Value | Type | Raw Data | Description | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 31 | 31 是数据包 ID | +| 2 | 定位状态 | uint8 | 00 |`0x00`: 定位成功。
`0x01`: GNSS 扫描超时。
`0x02`: Wi-Fi 扫描超时。
`0x03`: Wi-Fi + GNSS 扫描超时。
`0x04`: GNSS + Wi-Fi 扫描超时。
`0x05`: Bluetooth 扫描超时。
`0x06`: Bluetooth + Wi-Fi 扫描超时。
`0x07`: Bluetooth + GNSS 扫描超时。
`0x08`: Bluetooth + Wi-Fi + GNSS 扫描超时。
`0x09`: 位置服务器解析 GNSS 位置失败。
`0x0A`: 位置服务器解析 Wi-Fi 位置失败。
`0x0B`: 位置服务器解析 Bluetooth 位置失败。
`0x0C`: 由于精度较差导致位置解析失败。
`0x0D`: 时间同步失败。
`0x0E`: 由于星历(Almanac)过旧导致失败。
`0x0F`: GNSS + Bluetooth 扫描超时。 | +| 3~4 | 事件状态 | uint16 | 0000 |`0x0000` = 未触发任何事件
Bit 0: false
Bit 1: 开始移动事件
Bit 2: 结束移动事件
Bit 3: 静止事件
Bit 4: 震动事件
Bit 5: 温度事件
Bit 6: 光照事件
Bit 7: SOS 事件
Bit 8: 单击事件
Bit 9: 拆卸事件

转换为十六进制:
`0x0001`: 开始移动事件
`0x0002`: 结束移动事件
`0x0004`: 静止事件
`0x0008`: 震动事件
`0x0010`: 温度事件
`0x0020`: 光照事件
`0x0040`: SOS 事件
`0x0080`: 单击事件
`0x0100`: 拆卸事件 | +| 5~8 | UTC 时间戳 | uint32 | 694B3DB0 | `0x694B3DB0` = 1766538672(DEC) 秒

转换为 UTC 时间:
2025-12-24 01:11:12 | +| 9~10 | 加速度计 X | int16 | 003a | `0x003A` = 58 mg | +| 11~12 | 加速度计 Y | int16 | 039d | `0x039D` = 925 mg | +| 13~14 | 加速度计 Z | int16 | fe84 | `0xFE84` = -380 mg | +| 15 | 电池电量 | uint8 | 62 | `0x62` = 98% | + +### 定位状态数据包(加速度计关闭,0x32) + +定位状态数据包包含定位状态以及事件状态和电池信息。帧 ID 为 `0x32`,总长度为 9 字节。 + +| 0x32 | Byte2 | Byte3~4 | Byte5~8 | Byte9 | +| :--: | :---: | :-----: | :-----: | :---: | +| ID | 定位状态 | 事件状态 | UTC 时间戳 | 电池电量 | + +**原始载荷示例** + +`32 00 0100 694b3db0 62` + +| Byte | Value | Type | Raw Data | Description | +| :---: | :--- | :---: | :---: | :--- | +| 1 | 帧 ID | uint8 | 32 | 32 是数据包 ID | +| 2 | 定位状态 | uint8 | 00 |`0x00`: 定位成功。
`0x01`: GNSS 扫描超时。
`0x02`: Wi-Fi 扫描超时。
`0x03`: Wi-Fi + GNSS 扫描超时。
`0x04`: GNSS + Wi-Fi 扫描超时。
`0x05`: Bluetooth 扫描超时。
`0x06`: Bluetooth + Wi-Fi 扫描超时。
`0x07`: Bluetooth + GNSS 扫描超时。
`0x08`: Bluetooth + Wi-Fi + GNSS 扫描超时。
`0x09`: 位置服务器解析 GNSS 位置失败。
`0x0A`: 位置服务器解析 Wi-Fi 位置失败。
`0x0B`: 位置服务器解析 Bluetooth 位置失败。
`0x0C`: 由于精度较差导致位置解析失败。
`0x0D`: 时间同步失败。
`0x0E`: 由于星历(Almanac)过旧导致失败。
`0x0F`: GNSS + Bluetooth 扫描超时。 | +| 3~4 | 事件状态 | uint16 | 0100 | `0x0000` = 未触发任何事件
Bit 0: false
Bit 1: 开始移动事件
Bit 2: 结束移动事件
Bit 3: 静止事件
Bit 4: 震动事件
Bit 5: 温度事件
Bit 6: 光照事件
Bit 7: SOS 事件
Bit 8: 单击事件
Bit 9: 拆卸事件

转换为十六进制:
`0x0001`: 开始移动事件
`0x0002`: 结束移动事件
`0x0004`: 静止事件
`0x0008`: 震动事件
`0x0010`: 温度事件
`0x0020`: 光照事件
`0x0040`: SOS 事件
`0x0080`: 单击事件
`0x0100`: 拆卸事件 | +| 5~8 | UTC 时间戳 | uint32 | 694B3DB0 | `0x694B3DB0` = 1766538672(DEC) 秒

转换为 UTC 时间:
2025-12-24 01:11:12 | +| 9 | 电池电量 | uint8 | 62 | `0x62` = 98% | + +## 下行数据包,FPort=5 + +该追踪器支持通过 LoRaWAN 下发一些命令来调整参数。如果设备处于休眠状态,下行命令会在设备下一次唤醒并上传数据时生效。 + +由于 LoRaWAN Class A 的特性,下行窗口只会在上行之后打开,因此命令并非实时生效。例如,如果上报间隔设置为 10 分钟,设备可能需要等待最长 10 分钟,才能在下一次发送窗口中接收到下行命令。 + +**注意:FPort=5** + +### 请求设备状态数据包 (0x8F) + +|0x8F| +| - | +|ID| + +示例: + +8F:请求最新的设备状态和定位数据包。 + +### 设置工作模式与定位策略 (0x90) + +|0x90|Byte2|Byte3|Byte4~5|Byte6~7|Byte8~9| +| - | :- | :- | :- | :- | :- | +|ID|工作模式|定位策略|心跳间隔|周期模式上行间隔|事件模式上行间隔| + +|Byte10|Byte11|Byte12|Byte13|Byte14|Byte15~30| +| - | - | - | - | - | :- | +|启用三轴加速度计|启用拆卸告警|GNSS 扫描超时 (S)|iBeacon 扫描超时 (S)|UUID 过滤有效字节数|UUID 过滤| + +注意: +心跳间隔 / 周期模式上行间隔 / 事件模式上行间隔的单位:**分钟** + +示例: + +`90 01 01 02d0 0014 0005 01 01 1e 0a 10 00000000000000000000000000000000` + + +|**Byte**|**Value**|**Type**|**Raw Data**|**Description**| +| - | - | - | - | - | +|1|帧 ID|uint8|90|90 是数据包 ID| +|2|工作模式|uint8|01|01 = 周期模式
`00`: 待机模式
`01`: 周期模式
`02`: 事件模式| +|3|定位策略|uint8|01|`00`: 仅 GNSS
`01`: 仅 Wi-Fi
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: 仅 Bluetooth
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +|4~5|心跳间隔 | uint16 | 02d0 | `0x02D0` = 720 分钟| +|6~7|周期模式上行间隔|uint16|0014|`0x0014` = 20 分钟 | +|8~9|事件模式上行间隔|uint16|0005|`0x0005` = 5 分钟
当未触发事件时,将每 5 分钟上传一次数据。
| +|10|启用三轴加速度计|uint8|01|`00`: 禁用
`01`: 启用| +|11|启用拆卸告警|uint8|01|`00`: 禁用
`01`: 启用| +|12|GNSS 扫描超时|uint8|1E|`0x1E` = 30 秒 | +|13|iBeacon 扫描超时|uint8|0A|`0x0A` = 10 秒 | +|14|UUID 过滤有效字节数|uint8|10| UUID 过滤中有效字节的数量 (0–16)| +|15~30|UUID 过滤| 16 bytes | 0000000000000000
0000000000000000 | 16 字节 Bluetooth UUID 过滤。只有前 N 个字节(由 byte30 定义)是有效的| + + +### 设置事件模式阈值 (0x91) + +|0x91|Byte2|Byte3~4|Byte5~6|Byte7|Byte8~9| +| - | :- | :- | :- | :- | :- | +|ID|启用运动事件|三轴运动阈值|运动时上行间隔|启用静止事件|静止超时时间| + +|Byte10|Byte11~12| +| - | :- | +|启用震动事件|三轴震动阈值| + + +示例: + +`91 01 001e 0005 01 01 2c` + +|**Byte**|**值**|**类型**|**原始数据**|**描述**| +| - | - | - | - | - | +|1|帧 ID|uint8|91|91 是数据包 ID| +|2|启用运动事件|uint8|01|`00`: 禁用
`01`: 启用| +|3~4|三轴运动阈值|uint16|001e|`0x001E` = 30 mg
当加速度超过 30 mg 时,设备判定为处于运动状态
| +|5~6|运动时上行间隔|uint16|0005|`0x0005` = 5 分钟
检测到运动时,上报间隔为 5 分钟
| +|7|启用静止事件|uint8|01|`00`: 禁用
`01`: 启用| +|8~9|静止超时时间|uint16|012c|`0x012C` = 300 分钟
如果设备保持静止超过 300 分钟,将触发静止事件
| +|10|启用震动事件|uint8|01|`00`: 禁用
`01`: 启用| +|11~12|三轴震动阈值|uint16|012c|`0x012C` = 300 mg
当加速度超过 300 mg 时,将触发震动事件
| + +### 请求设备状态数据包 (0x92) + +|0x92| +| - | +|ID| + +示例: + +92:强制进行一次 GNSS 定位修正。 + +### 设置工作模式 & 定位策略 & 事件模式阈值 (0x97) + +|0x97|Byte2|Byte3|Byte4~5|Byte6~7|Byte8~9| +| - | :- | :- | :- | :- | :- | +|ID|工作模式|定位策略|心跳间隔|周期模式上行间隔|事件模式上行间隔| + +|Byte10|Byte11|Byte12|Byte13|Byte14|Byte15~30| +| - | :- | :- | :- | :- | :- | +|启用三轴加速度计|启用拆卸告警|GNSS 扫描超时时间|iBeacon 扫描超时时间|UUID 过滤有效字节数|UUID 过滤器| + +#### 运动事件设置 +|Byte31|Byte32~33|Byte34~35| +| - | :- | :- | +|启用运动事件|三轴运动阈值|运动时上行间隔| + +#### 静止事件设置 +|Byte36|Byte37~38| +| - | :- | +|启用静止事件|静止超时时间| + + +#### 震动事件设置 +|Byte39|Byte40~41| +| - | :- | +|启用震动事件|三轴震动阈值| + +示例: + +`97 01 02 003c 001e 000a 01 01 0a 05 10 00000000000000000000000000000000 01 001e 0005 01 012c 01 012c` + +|**Byte**|**值**|**类型**|**原始数据**|**描述**| +| - | - | - | - | - | +|1|帧 ID|uint8|97|97 是数据包 ID| +|2|工作模式|uint8|01|`00`: 待机模式
`01`: 周期模式
`02`: 事件模式| +|3|定位策略|uint8|02|`00`: 仅 GNSS
`01`: 仅 Wi-Fi
`02`: Wi-Fi + GNSS
`03`: GNSS + Wi-Fi
`04`: 仅 Bluetooth
`05`: Bluetooth + Wi-Fi
`06`: Bluetooth + GNSS
`07`: Bluetooth + Wi-Fi + GNSS
`08`: GNSS + Bluetooth | +|4~5|心跳间隔|uint16|003c|`0x003C` = 60 秒| +|6~7|周期模式上行间隔|uint16|001e|`0x001E` = 30 秒| +|8~9|事件模式上行间隔|uint16|000a|`0x000A` = 10 分钟
当没有事件被触发时,每 10 分钟上传一次数据。
| +|10|启用三轴加速度计|uint8|01|`00`: 禁用
`01`: 启用| +|11|启用拆卸告警|uint8|01|`00`: 禁用
`01`: 启用| +|12|GNSS 扫描超时时间|uint8|0a|`0x0A` = 10 秒| +|13|iBeacon 扫描超时时间|uint8|05|`0x05` = 5 秒| +|14|UUID 过滤有效字节数|uint8|10|`0x10` = 16 字节| +|15~30|UUID 过滤器|byte[16]|0000000000000000
0000000000000000|UUID 过滤值(16 字节)
| +|31|启用运动事件|uint8|01|`00`: 禁用
`01`: 启用| +|32~33|三轴运动阈值|uint16|001e|`0x001E` = 30 mg | +|34~35|运动时上行间隔|uint16|0005|`0x0005` = 5 分钟
检测到运动时,上报间隔为 5 分钟| +|36|启用静止事件|uint8|01|`00`: 禁用
`01`: 启用| +|37~38|静止超时时间|uint16|012c|`0x012C` = 300 分钟 | +|39|启用震动事件|uint8|01|`00`: 禁用
`01`: 启用| +|40~41|三轴震动阈值|uint16|012c|`0x012C` = 300 mg | + +## 技术支持与产品讨论 + +感谢您选择我们的产品!我们将为您提供多种支持,确保您在使用我们产品的过程中尽可能顺畅。我们提供多种沟通渠道,以满足不同的偏好和需求。 + +
+ + +
+ +
+ + +
\ No newline at end of file diff --git a/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/cn_SenseCAP_T2000_intro.md b/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/cn_SenseCAP_T2000_intro.md index 8c31508719c7b..a7ab408aaf5dd 100644 --- a/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/cn_SenseCAP_T2000_intro.md +++ b/sites/zh-CN/docs/Sensor/SenseCAP/SenseCAP_T2000_Tracker/cn_SenseCAP_T2000_intro.md @@ -1,29 +1,31 @@ --- -description: SenseCAP T2000 追踪器 -title: SenseCAP T2000 追踪器 +description: SenseCAP T2000 Tracker +title: SenseCAP T2000 Tracker keywords: - Tracker - SenseCAP image: https://files.seeedstudio.com/wiki/wiki-platform/S-tempor.png slug: /sensecap_t2000_tracker last_update: - date: 1/28/2026 + date: 3/12/2026 author: Janet -createdAt: '2025-12-01' -updatedAt: '2026-03-03' +createdAt: '2025-11-27' +updatedAt: '2026-03-12' url: https://wiki.seeedstudio.com/cn/sensecap_t2000_tracker/ ---

pir

-[**SenseCAP T2000 追踪器**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html)是一款工业级 LoRaWAN® 资产追踪器,支持 GNSS、蓝牙和 Wi-Fi 定位,可在室内外环境中提供可靠的追踪功能。它具有 IP67 防护等级,内置 3 轴加速度计可检测运动状态,以及防拆按钮,当设备被移除时会触发最高优先级警报。T2000-A 和 T2000-B 支持长续航电池操作,而配备可充电电池的太阳能供电 T2000-C 确保持续的户外使用,使该系列产品成为长期免维护资产追踪的理想选择。 +[**SenseCAP T2000 Tracker**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html),一款工业级 LoRaWAN® 资产追踪器,支持 GNSS、Bluetooth 和 Wi-Fi 定位,可在室内和室外环境中实现可靠追踪。它具备 IP67 防护等级,内置可检测运动状态的三轴加速度计,以及在设备被拆除时触发最高优先级告警的防拆按钮。T2000-A 和 T2000-B 支持长续航电池供电,而采用太阳能供电并配备可充电电池的 T2000-C 可确保持续的户外使用,使该系列非常适合长期、免维护的资产追踪应用。 -

SenseCAP T2000 追踪器目录

+

SenseCAP T2000 Tracker 目录

### 集成 LoRaWAN® 网络服务器 @@ -36,7 +38,7 @@ url: https://wiki.seeedstudio.com/cn/sensecap_t2000_tracker/ ## 技术支持与产品讨论 -感谢您选择我们的产品!我们在此为您提供不同的支持,以确保您使用我们产品的体验尽可能顺畅。我们提供多种沟通渠道,以满足不同的偏好和需求。 +感谢您选择我们的产品!我们将为您提供多种支持,确保您在使用我们产品的过程中尽可能顺畅。我们提供多种沟通渠道,以满足不同的偏好和需求。
diff --git a/sites/zh-CN/docs/Sensor/SenseCAP/cn_SenseCAP_Decoder.md b/sites/zh-CN/docs/Sensor/SenseCAP/cn_SenseCAP_Decoder.md index bab6e3573783e..2382fed0fa8e5 100644 --- a/sites/zh-CN/docs/Sensor/SenseCAP/cn_SenseCAP_Decoder.md +++ b/sites/zh-CN/docs/Sensor/SenseCAP/cn_SenseCAP_Decoder.md @@ -1,29 +1,29 @@ --- -description: SenseCAP 解码器 +description: SenseCAP_Decoder title: SenseCAP 解码器 keywords: - SenseCAP_Decoder image: https://files.seeedstudio.com/wiki/wiki-platform/S-tempor.png slug: /SenseCAP_Decoder last_update: - date: 1/26/2026 + date: 3/12/2026 author: Janet createdAt: '2023-08-24' -updatedAt: '2026-03-03' +updatedAt: '2026-03-12' url: https://wiki.seeedstudio.com/cn/SenseCAP_Decoder/ --- -SenseCAP 解码器用于解码从 SenseCAP LoRaWAN® 设备发送的 LoRaWAN 消息。解码后,用户的应用程序将获得更友好和可读的消息。 +SenseCAP 解码器用于解码由 SenseCAP LoRaWAN® 设备发送的 LoRaWAN 消息。解码后,用户的应用程序将获得更加友好且易于阅读的消息。 ### SenseCAP T1000 追踪器 -[**SenseCAP T1000**](https://www.seeedstudio.com/sensecap-t1000-tracker?utm_source=emailsig&utm_medium=emailsig&utm_campaign=emailsig) 是一款紧凑的 LoRaWAN® 追踪器,利用 GNSS/Wi-Fi/蓝牙进行精确的室内外位置追踪。它具有自适应地理能力、本地数据存储和令人印象深刻的数月电池续航。此外,它还配备了温度、光线和运动传感器,使其非常适合各种基于位置的应用。 +[**SenseCAP T1000**](https://www.seeedstudio.com/sensecap-t1000-tracker?utm_source=emailsig&utm_medium=emailsig&utm_campaign=emailsig) 是一款紧凑型 LoRaWAN® 追踪器,利用 GNSS/Wi-Fi/Bluetooth 实现精确的室内与室外位置追踪。它具备自适应地理能力、本地数据存储以及长达数月的电池续航。此外,它还配备温度、光照和运动传感器,非常适合多种基于位置的应用场景。

pir

@@ -31,851 +31,24 @@ SenseCAP 解码器用于解码从 SenseCAP LoRaWAN® 设备发送的 LoRaWAN 消
-适用于 TTN(ChirpStack V4) - -```cpp -function decodeUplink (input) { - const bytes = input['bytes'] - const fport = parseInt(input['fPort']) - const bytesString = bytes2HexString(bytes) - const originMessage = bytesString.toLocaleUpperCase() - const decoded = { - valid: true, - err: 0, - payload: bytesString, - messages: [] - } - if (fport === 199 || fport === 192) { - decoded.messages.push({fport: fport, payload: bytesString}) - return { data: decoded } - } - if (fport !== 5) { - decoded.valid = false - return { data: decoded } - } - let measurement = messageAnalyzed(originMessage) - if (measurement.length === 0) { - decoded.valid = false - return { data: decoded } - } - - for (let message of measurement) { - if (message.length === 0) { - continue - } - let elements = [] - for (let element of message) { - if (element.errorCode) { - decoded.err = element.errorCode - decoded.errMessage = element.error - } else { - elements.push(element) - } - } - if (elements.length > 0) { - decoded.messages.push(elements) - } - } - // decoded.messages = measurement - return { data: decoded } -} - -function messageAnalyzed (messageValue) { - try { - let frames = unpack(messageValue) - let measurementResultArray = [] - for (let i = 0; i < frames.length; i++) { - let item = frames[i] - let dataId = item.dataId - let dataValue = item.dataValue - let measurementArray = deserialize(dataId, dataValue) - measurementResultArray.push(measurementArray) - } - return measurementResultArray - } catch (e) { - return e.toString() - } -} - -function unpack (messageValue) { - let frameArray = [] - - for (let i = 0; i < messageValue.length; i++) { - let remainMessage = messageValue - let dataId = remainMessage.substring(0, 2).toUpperCase() - let dataValue - let dataObj = {} - let packageLen - switch (dataId) { - case '01': - packageLen = 94 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '02': - packageLen = 32 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '03': - packageLen = 64 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '04': - packageLen = 20 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '05': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '06': - packageLen = 44 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '07': - packageLen = 84 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '08': - packageLen = 70 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '09': - packageLen = 36 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0A': - packageLen = 76 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0B': - packageLen = 62 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0C': - packageLen = 2 - if (remainMessage.length < packageLen) { - return frameArray - } - break - case '0D': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0E': - packageLen = getInt(remainMessage.substring(8, 10)) * 2 + 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, 8) + remainMessage.substring(10, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '0F': - packageLen = 34 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '10': - packageLen = 26 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - case '11': - packageLen = 28 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) - dataObj = { - 'dataId': dataId, 'dataValue': dataValue - } - break - default: - return frameArray - } - if (dataValue.length < 2) { - break - } - frameArray.push(dataObj) - } - return frameArray -} - -function deserialize (dataId, dataValue) { - let measurementArray = [] - let eventList = [] - let measurement = {} - let collectTime = 0 - let groupId = 0 - let shardFlag = {} - let payload = '' - let result = [] - let dataArr = [] - switch (dataId) { - case '01': - measurementArray = getUpShortInfo(dataValue) - measurementArray.push(...getMotionSetting(dataValue.substring(30, 40))) - measurementArray.push(...getStaticSetting(dataValue.substring(40, 46))) - measurementArray.push(...getShockSetting(dataValue.substring(46, 52))) - measurementArray.push(...getTempSetting(dataValue.substring(52, 72))) - measurementArray.push(...getLightSetting(dataValue.substring(72, 92))) - break - case '02': - measurementArray = getUpShortInfo(dataValue) - break - case '03': - measurementArray.push(...getMotionSetting(dataValue.substring(0, 10))) - measurementArray.push(...getStaticSetting(dataValue.substring(10, 16))) - measurementArray.push(...getShockSetting(dataValue.substring(16, 22))) - measurementArray.push(...getTempSetting(dataValue.substring(22, 42))) - measurementArray.push(...getLightSetting(dataValue.substring(42, 62))) - break - case '04': - let interval = 0 - let workMode = getInt(dataValue.substring(0, 2)) - let heartbeatInterval = getMinsByMin(dataValue.substring(4, 8)) - let periodicInterval = getMinsByMin(dataValue.substring(8, 12)) - let eventInterval = getMinsByMin(dataValue.substring(12, 16)) - switch (workMode) { - case 0: - interval = heartbeatInterval - break - case 1: - interval = periodicInterval - break - case 2: - interval = eventInterval - break - } - measurementArray = [ - {measurementId: '3940', type: 'Work Mode', measurementValue: workMode}, - {measurementId: '3942', type: 'Heartbeat Interval', measurementValue: heartbeatInterval}, - {measurementId: '3943', type: 'Periodic Interval', measurementValue: periodicInterval}, - {measurementId: '3944', type: 'Event Interval', measurementValue: eventInterval}, - {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(16, 18))}, - {measurementId: '3900', type: 'Uplink Interval', measurementValue: interval} - ] - break; - case '05': - measurementArray = [ - {measurementId: '3000', type: 'Battery', measurementValue: getBattery(dataValue.substring(0, 2))}, - {measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(dataValue.substring(2, 4))}, - {measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(dataValue.substring(4, 6))}, - {measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(dataValue.substring(6, 8))} - ] - break - case '06': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} - ] - break - case '07': - eventList = getEventStatus(dataValue.substring(0, 6)) - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} - ] - break - case '08': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} - ] - break - case '09': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} - ] - break - case '0A': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} - ] - break - case '0B': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, - ] - break - case '0D': - let errorCode = getInt(dataValue) - let error = '' - switch (errorCode) { - case 1: - error = 'FAILED TO OBTAIN THE UTC TIMESTAMP' - break - case 2: - error = 'ALMANAC TOO OLD' - break - case 3: - error = 'DOPPLER ERROR' - break - } - measurementArray.push({errorCode, error}) - break - case '0E': - shardFlag = getShardFlag(dataValue.substring(0, 2)) - groupId = getInt(dataValue.substring(2, 6)) - payload = dataValue.substring(6) - measurement = { - measurementId: '6152', - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'gnss-ng payload', - measurementValue: payload - } - measurementArray.push(measurement) - break - case '0F': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - shardFlag = getShardFlag(dataValue.substring(26, 28)) - groupId = getInt(dataValue.substring(28, 32)) - measurementArray.push({ - measurementId: '4200', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Event Status', - measurementValue: getEventStatus(dataValue.substring(0, 6)) - }) - measurementArray.push({ - measurementId: '4097', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) - }) - measurementArray.push({ - measurementId: '4199', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) - }) - measurementArray.push({ - measurementId: '3000', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) - }) - break - case '10': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - shardFlag = getShardFlag(dataValue.substring(18, 20)) - groupId = getInt(dataValue.substring(20, 24)) - measurementArray.push({ - measurementId: '4200', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Event Status', - measurementValue: getEventStatus(dataValue.substring(0, 6)) - }) - measurementArray.push({ - measurementId: '3000', - timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), - groupId: groupId, - index: shardFlag.index, - count: shardFlag.count, - type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(16, 18)) - }) - break - case '11': - collectTime = getUTCTimestamp(dataValue.substring(8, 16)) - measurementArray.push({ - measurementId: '3576', - timestamp: collectTime, - type: 'Positing Status', - measurementValue: '' + getPositingStatus(dataValue.substring(0, 2)) - }) - measurementArray.push({ - timestamp: collectTime, - measurementId: '4200', - type: 'Event Status', - measurementValue: getEventStatus(dataValue.substring(2, 8)) - }) - if (!isNaN(parseFloat(getSensorValue(dataValue.substring(16, 20), 10)))) { - measurementArray.push({ - timestamp: collectTime, - measurementId: '4097', - type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) - }) - } - if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { - measurementArray.push({ - timestamp: collectTime, - measurementId: '4199', - type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) - }) - } - measurementArray.push({ - timestamp: collectTime, - measurementId: '3000', - type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) - }) - break - } - return measurementArray -} - -function getMotionId (str) { - return getInt(str) -} - -function getPositingStatus (str) { - return getInt(str) -} - -function getUpShortInfo (messageValue) { - return [ - { - measurementId: '3000', type: 'Battery', measurementValue: getBattery(messageValue.substring(0, 2)) - }, { - measurementId: '3502', type: 'Firmware Version', measurementValue: getSoftVersion(messageValue.substring(2, 6)) - }, { - measurementId: '3001', type: 'Hardware Version', measurementValue: getHardVersion(messageValue.substring(6, 10)) - }, { - measurementId: '3940', type: 'Work Mode', measurementValue: getWorkingMode(messageValue.substring(10, 12)) - }, { - measurementId: '3965', type: 'Positioning Strategy', measurementValue: getPositioningStrategy(messageValue.substring(12, 14)) - }, { - measurementId: '3942', type: 'Heartbeat Interval', measurementValue: getMinsByMin(messageValue.substring(14, 18)) - }, { - measurementId: '3943', type: 'Periodic Interval', measurementValue: getMinsByMin(messageValue.substring(18, 22)) - }, { - measurementId: '3944', type: 'Event Interval', measurementValue: getMinsByMin(messageValue.substring(22, 26)) - }, { - measurementId: '3945', type: 'Sensor Enable', measurementValue: getInt(messageValue.substring(26, 28)) - }, { - measurementId: '3941', type: 'SOS Mode', measurementValue: getSOSMode(messageValue.substring(28, 30)) - } - ] -} - -function getMotionSetting (str) { - return [ - {measurementId: '3946', type: 'Motion Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3947', type: 'Any Motion Threshold', measurementValue: getSensorValue(str.substring(2, 6), 1)}, - {measurementId: '3948', type: 'Motion Start Interval', measurementValue: getMinsByMin(str.substring(6, 10))}, - ] -} - -function getStaticSetting (str) { - return [ - {measurementId: '3949', type: 'Static Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3950', type: 'Device Static Timeout', measurementValue: getMinsByMin(str.substring(2, 6))} - ] -} - -function getShockSetting (str) { - return [ - {measurementId: '3951', type: 'Shock Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3952', type: 'Shock Threshold', measurementValue: getInt(str.substring(2, 6))} - ] -} - -function getTempSetting (str) { - return [ - {measurementId: '3953', type: 'Temp Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3954', type: 'Event Temp Interval', measurementValue: getMinsByMin(str.substring(2, 6))}, - {measurementId: '3955', type: 'Event Temp Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))}, - {measurementId: '3956', type: 'Temp ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)}, - {measurementId: '3957', type: 'Temp ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)}, - {measurementId: '3958', type: 'Temp Warning Type', measurementValue: getInt(str.substring(18, 20))} - ] -} - -function getLightSetting (str) { - return [ - {measurementId: '3959', type: 'Light Enable', measurementValue: getInt(str.substring(0, 2))}, - {measurementId: '3960', type: 'Event Light Interval', measurementValue: getMinsByMin(str.substring(2, 6))}, - {measurementId: '3961', type: 'Event Light Sample Interval', measurementValue: getSecondsByInt(str.substring(6, 10))}, - {measurementId: '3962', type: 'Light ThMax', measurementValue: getSensorValue(str.substring(10, 14), 10)}, - {measurementId: '3963', type: 'Light ThMin', measurementValue: getSensorValue(str.substring(14, 18), 10)}, - {measurementId: '3964', type: 'Light Warning Type', measurementValue: getInt(str.substring(18, 20))} - ] -} - -function getShardFlag (str) { - let bitStr = getByteArray(str) - return { - count: parseInt(bitStr.substring(0, 4), 2), - index: parseInt(bitStr.substring(4), 2) - } -} - -function getBattery (batteryStr) { - return loraWANV2DataFormat(batteryStr) -} -function getSoftVersion (softVersion) { - return `${loraWANV2DataFormat(softVersion.substring(0, 2))}.${loraWANV2DataFormat(softVersion.substring(2, 4))}` -} -function getHardVersion (hardVersion) { - return `${loraWANV2DataFormat(hardVersion.substring(0, 2))}.${loraWANV2DataFormat(hardVersion.substring(2, 4))}` -} - -function getSecondsByInt (str) { - return getInt(str) -} - -function getMinsByMin (str) { - return getInt(str) -} - -function getSensorValue (str, dig) { - if (str === '8000') { - return null - } else { - return loraWANV2DataFormat(str, dig) - } -} - -function bytes2HexString (arrBytes) { - var str = '' - for (var i = 0; i < arrBytes.length; i++) { - var tmp - var num = arrBytes[i] - if (num < 0) { - tmp = (255 + num + 1).toString(16) - } else { - tmp = num.toString(16) - } - if (tmp.length === 1) { - tmp = '0' + tmp - } - str += tmp - } - return str -} -function loraWANV2DataFormat (str, divisor = 1) { - let strReverse = bigEndianTransform(str) - let str2 = toBinary(strReverse) - if (str2.substring(0, 1) === '1') { - let arr = str2.split('') - let reverseArr = arr.map((item) => { - if (parseInt(item) === 1) { - return 0 - } else { - return 1 - } - }) - str2 = parseInt(reverseArr.join(''), 2) + 1 - return '-' + str2 / divisor - } - return parseInt(str2, 2) / divisor -} - -function bigEndianTransform (data) { - let dataArray = [] - for (let i = 0; i < data.length; i += 2) { - dataArray.push(data.substring(i, i + 2)) - } - return dataArray -} - -function toBinary (arr) { - let binaryData = arr.map((item) => { - let data = parseInt(item, 16) - .toString(2) - let dataLength = data.length - if (data.length !== 8) { - for (let i = 0; i < 8 - dataLength; i++) { - data = `0` + data - } - } - return data - }) - return binaryData.toString().replace(/,/g, '') -} - -function getSOSMode (str) { - return loraWANV2DataFormat(str) -} - -function getMacAndRssiObj (pair) { - let pairs = [] - if (pair.length % 14 === 0) { - for (let i = 0; i < pair.length; i += 14) { - let mac = getMacAddress(pair.substring(i, i + 12)) - if (mac) { - let rssi = getInt8RSSI(pair.substring(i + 12, i + 14)) - pairs.push({mac: mac, rssi: rssi}) - } else { - continue - } - } - } - return pairs -} - -function getMacAddress (str) { - if (str.toLowerCase() === 'ffffffffffff') { - return null - } - let macArr = [] - for (let i = 1; i < str.length; i++) { - if (i % 2 === 1) { - macArr.push(str.substring(i - 1, i + 1)) - } - } - let mac = '' - for (let i = 0; i < macArr.length; i++) { - mac = mac + macArr[i] - if (i < macArr.length - 1) { - mac = mac + ':' - } - } - return mac -} - -function getInt8RSSI (str) { - return loraWANV2DataFormat(str) -} - -function getInt (str) { - return parseInt(str, 16) -} - -function getEventStatus (str) { - // return getInt(str) - let bitStr = getByteArray(str) - let bitArr = [] - for (let i = 0; i < bitStr.length; i++) { - bitArr[i] = bitStr.substring(i, i + 1) - } - bitArr = bitArr.reverse() - let event = [] - for (let i = 0; i < bitArr.length; i++) { - if (bitArr[i] !== '1') { - continue - } - switch (i){ - case 0: - event.push({id:1, eventName:"Start moving event."}) - break - case 1: - event.push({id:2, eventName:"End movement event."}) - break - case 2: - event.push({id:3, eventName:"Motionless event."}) - break - case 3: - event.push({id:4, eventName:"Shock event."}) - break - case 4: - event.push({id:5, eventName:"Temperature event."}) - break - case 5: - event.push({id:6, eventName:"Light event."}) - break - case 6: - event.push({id:7, eventName:"SOS event."}) - break - case 7: - event.push({id:8, eventName:"Press once event."}) - break - } - } - return event -} - -function getByteArray (str) { - let bytes = [] - for (let i = 0; i < str.length; i += 2) { - bytes.push(str.substring(i, i + 2)) - } - return toBinary(bytes) -} - -function getWorkingMode (workingMode) { - return getInt(workingMode) -} - -function getPositioningStrategy (strategy) { - return getInt(strategy) -} - -function getUTCTimestamp(str){ - return parseInt(loraWANV2PositiveDataFormat(str)) * 1000 -} - -function loraWANV2PositiveDataFormat (str, divisor = 1) { - let strReverse = bigEndianTransform(str) - let str2 = toBinary(strReverse) - return parseInt(str2, 2) / divisor -} -``` - -
- -
- -适用于 Helium +适用于 TTN(ChirpStack V4) ```cpp -function Decoder (bytes, port) { +function decodeUplink (input) { + const bytes = input['bytes'] + const fport = parseInt(input['fPort']) const bytesString = bytes2HexString(bytes) const originMessage = bytesString.toLocaleUpperCase() - const fport = parseInt(port) const decoded = { valid: true, err: 0, payload: bytesString, messages: [] } - if (fport === 199 || fport === 192) { decoded.messages.push({fport: fport, payload: bytesString}) return { data: decoded } } - if (fport !== 5) { - decoded.valid = false - return { data: decoded } - } - let measurement = messageAnalyzed(originMessage) if (measurement.length === 0) { decoded.valid = false @@ -899,7 +72,6 @@ function Decoder (bytes, port) { decoded.messages.push(elements) } } - // decoded.messages = measurement return { data: decoded } } @@ -922,7 +94,6 @@ function messageAnalyzed (messageValue) { function unpack (messageValue) { let frameArray = [] - for (let i = 0; i < messageValue.length; i++) { let remainMessage = messageValue let dataId = remainMessage.substring(0, 2).toUpperCase() @@ -931,148 +102,93 @@ function unpack (messageValue) { let packageLen switch (dataId) { case '01': - packageLen = 94 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 94) + messageValue = remainMessage.substring(94) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '02': - packageLen = 32 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 32) + messageValue = remainMessage.substring(32) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '03': - packageLen = 64 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 64) + messageValue = remainMessage.substring(64) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '04': - packageLen = 20 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 20) + messageValue = remainMessage.substring(20) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '05': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 10) + messageValue = remainMessage.substring(10) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '06': - packageLen = 44 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 44) + messageValue = remainMessage.substring(44) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '07': - packageLen = 84 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 84) + messageValue = remainMessage.substring(84) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '08': - packageLen = 70 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 70) + messageValue = remainMessage.substring(70) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '09': - packageLen = 36 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 36) + messageValue = remainMessage.substring(36) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0A': - packageLen = 76 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 76) + messageValue = remainMessage.substring(76) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0B': - packageLen = 62 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 62) + messageValue = remainMessage.substring(62) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0C': - packageLen = 2 - if (remainMessage.length < packageLen) { - return frameArray - } break case '0D': - packageLen = 10 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 10) + messageValue = remainMessage.substring(10) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '0E': packageLen = getInt(remainMessage.substring(8, 10)) * 2 + 10 - if (remainMessage.length < packageLen) { - return frameArray - } dataValue = remainMessage.substring(2, 8) + remainMessage.substring(10, packageLen) messageValue = remainMessage.substring(packageLen) dataObj = { @@ -1080,34 +196,50 @@ function unpack (messageValue) { } break case '0F': - packageLen = 34 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 34) + messageValue = remainMessage.substring(34) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '10': - packageLen = 26 - if (remainMessage.length < packageLen) { - return frameArray - } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + dataValue = remainMessage.substring(2, 26) + messageValue = remainMessage.substring(26) dataObj = { 'dataId': dataId, 'dataValue': dataValue } break case '11': - packageLen = 28 - if (remainMessage.length < packageLen) { - return frameArray + dataValue = remainMessage.substring(2, 28) + messageValue = remainMessage.substring(28) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue } - dataValue = remainMessage.substring(2, packageLen) - messageValue = remainMessage.substring(packageLen) + break + case '1A': + dataValue = remainMessage.substring(2, 56) + messageValue = remainMessage.substring(56) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue + } + break + case '1B': + dataValue = remainMessage.substring(2, 96) + messageValue = remainMessage.substring(96) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue + } + break + case '1C': + dataValue = remainMessage.substring(2, 82) + messageValue = remainMessage.substring(82) + dataObj = { + 'dataId': dataId, 'dataValue': dataValue + } + break + case '1D': + dataValue = remainMessage.substring(2, 40) + messageValue = remainMessage.substring(40) dataObj = { 'dataId': dataId, 'dataValue': dataValue } @@ -1131,8 +263,7 @@ function deserialize (dataId, dataValue) { let groupId = 0 let shardFlag = {} let payload = '' - let result = [] - let dataArr = [] + let motionId = '' switch (dataId) { case '01': measurementArray = getUpShortInfo(dataValue) @@ -1188,59 +319,65 @@ function deserialize (dataId, dataValue) { break case '06': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '4197', timestamp: collectTime, motionId: motionId, type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, + {measurementId: '4198', timestamp: collectTime, motionId: motionId, type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, + {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(40, 42))} ] break case '07': eventList = getEventStatus(dataValue.substring(0, 6)) collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5001', timestamp: collectTime, motionId: motionId, type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, + {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(80, 82))} ] break case '08': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '4097', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, - {measurementId: '4199', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5002', timestamp: collectTime, motionId: motionId, type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, + {measurementId: '4097', timestamp: collectTime, motionId: motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId: motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(66, 68))} ] break case '09': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '4197', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, - {measurementId: '4198', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} + {measurementId: '4200', timestamp: collectTime, motionId: motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '4197', timestamp: collectTime, motionId: motionId, type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, + {measurementId: '4198', timestamp: collectTime, motionId: motionId, type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, + {measurementId: '3000', timestamp: collectTime, motionId: motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(32, 34))} ] break case '0A': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5001', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5001', timestamp: collectTime, motionId, type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(72, 74))} ] break case '0B': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray = [ - {measurementId: '4200', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, - {measurementId: '5002', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, - {measurementId: '3000', timestamp: collectTime, motionId: getMotionId(dataValue.substring(6, 8)), type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5002', timestamp: collectTime, motionId, type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(58, 60))}, ] break case '0D': @@ -1277,10 +414,11 @@ function deserialize (dataId, dataValue) { collectTime = getUTCTimestamp(dataValue.substring(8, 16)) shardFlag = getShardFlag(dataValue.substring(26, 28)) groupId = getInt(dataValue.substring(28, 32)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray.push({ measurementId: '4200', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, @@ -1290,42 +428,43 @@ function deserialize (dataId, dataValue) { measurementArray.push({ measurementId: '4097', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) + measurementValue: getSensorValue(dataValue.substring(16, 20), 10) }) measurementArray.push({ measurementId: '4199', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) + measurementValue: getSensorValue(dataValue.substring(20, 24)) }) measurementArray.push({ measurementId: '3000', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) + measurementValue: getBattery(dataValue.substring(24, 26)) }) break case '10': collectTime = getUTCTimestamp(dataValue.substring(8, 16)) shardFlag = getShardFlag(dataValue.substring(18, 20)) groupId = getInt(dataValue.substring(20, 24)) + motionId = getMotionId(dataValue.substring(6, 8)) measurementArray.push({ measurementId: '4200', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, @@ -1335,12 +474,12 @@ function deserialize (dataId, dataValue) { measurementArray.push({ measurementId: '3000', timestamp: collectTime, - motionId: getMotionId(dataValue.substring(6, 8)), + motionId, groupId: groupId, index: shardFlag.index, count: shardFlag.count, type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(16, 18)) + measurementValue: getBattery(dataValue.substring(16, 18)) }) break case '11': @@ -1348,8 +487,8 @@ function deserialize (dataId, dataValue) { measurementArray.push({ measurementId: '3576', timestamp: collectTime, - type: 'Positing Status', - measurementValue: '' + getPositingStatus(dataValue.substring(0, 2)) + type: 'Positioning Status', + measurementValue: getPositingStatus(dataValue.substring(0, 2)) }) measurementArray.push({ timestamp: collectTime, @@ -1362,7 +501,7 @@ function deserialize (dataId, dataValue) { timestamp: collectTime, measurementId: '4097', type: 'Air Temperature', - measurementValue: '' + getSensorValue(dataValue.substring(16, 20), 10) + measurementValue: getSensorValue(dataValue.substring(16, 20), 10) }) } if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { @@ -1370,14 +509,112 @@ function deserialize (dataId, dataValue) { timestamp: collectTime, measurementId: '4199', type: 'Light', - measurementValue: '' + getSensorValue(dataValue.substring(20, 24)) + measurementValue: getSensorValue(dataValue.substring(20, 24)) }) } measurementArray.push({ timestamp: collectTime, measurementId: '3000', type: 'Battery', - measurementValue: '' + getBattery(dataValue.substring(24, 26)) + measurementValue: getBattery(dataValue.substring(24, 26)) + }) + break + case '1A': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) + measurementArray = [ + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '4197', timestamp: collectTime, motionId, type: 'Longitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(16, 24), 1000000))}, + {measurementId: '4198', timestamp: collectTime, motionId, type: 'Latitude', measurementValue: parseFloat(getSensorValue(dataValue.substring(24, 32), 1000000))}, + {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(32, 36), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(36, 40))}, + {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(40, 44))}, + {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(44, 48))}, + {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(48, 52))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(52, 54))}, + ] + break + case '1B': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) + measurementArray = [ + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5001', timestamp: collectTime, motionId, type: 'Wi-Fi Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 72))}, + {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(72, 76), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(76, 80))}, + {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(80, 84))}, + {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(84, 88))}, + {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(88, 92))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(92, 94))} + ] + break + case '1C': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + motionId = getMotionId(dataValue.substring(6, 8)) + measurementArray = [ + {measurementId: '4200', timestamp: collectTime, motionId, type: 'Event Status', measurementValue: getEventStatus(dataValue.substring(0, 6))}, + {measurementId: '5002', timestamp: collectTime, motionId, type: 'BLE Scan', measurementValue: getMacAndRssiObj(dataValue.substring(16, 58))}, + {measurementId: '4097', timestamp: collectTime, motionId, type: 'Air Temperature', measurementValue: getSensorValue(dataValue.substring(58, 62), 10)}, + {measurementId: '4199', timestamp: collectTime, motionId, type: 'Light', measurementValue: getSensorValue(dataValue.substring(62, 66))}, + {measurementId: '4210', timestamp: collectTime, motionId, type: 'AccelerometerX', measurementValue: getSensorValue(dataValue.substring(66, 70))}, + {measurementId: '4211', timestamp: collectTime, motionId, type: 'AccelerometerY', measurementValue: getSensorValue(dataValue.substring(70, 74))}, + {measurementId: '4212', timestamp: collectTime, motionId, type: 'AccelerometerZ', measurementValue: getSensorValue(dataValue.substring(74, 78))}, + {measurementId: '3000', timestamp: collectTime, motionId, type: 'Battery', measurementValue: getBattery(dataValue.substring(78, 80))} + ] + break + case '1D': + collectTime = getUTCTimestamp(dataValue.substring(8, 16)) + measurementArray.push({ + measurementId: '3576', + timestamp: collectTime, + type: 'Positioning Status', + measurementValue: getPositingStatus(dataValue.substring(0, 2)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '4200', + type: 'Event Status', + measurementValue: getEventStatus(dataValue.substring(2, 8)) + }) + if (!isNaN(parseFloat(getSensorValue(dataValue.substring(16, 20), 10)))) { + measurementArray.push({ + timestamp: collectTime, + measurementId: '4097', + type: 'Air Temperature', + measurementValue: getSensorValue(dataValue.substring(16, 20), 10) + }) + } + if (!isNaN(parseFloat(getSensorValue(dataValue.substring(20, 24))))) { + measurementArray.push({ + timestamp: collectTime, + measurementId: '4199', + type: 'Light', + measurementValue: getSensorValue(dataValue.substring(20, 24)) + }) + } + measurementArray.push({ + timestamp: collectTime, + measurementId: '4210', + type: 'AccelerometerX', + measurementValue: getSensorValue(dataValue.substring(24, 28)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '4211', + type: 'AccelerometerY', + measurementValue: getSensorValue(dataValue.substring(28, 32)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '4212', + type: 'AccelerometerZ', + measurementValue: getSensorValue(dataValue.substring(32, 36)) + }) + measurementArray.push({ + timestamp: collectTime, + measurementId: '3000', + type: 'Battery', + measurementValue: getBattery(dataValue.substring(36, 38)) }) break } @@ -1389,6 +626,39 @@ function getMotionId (str) { } function getPositingStatus (str) { + let status = getInt(str) + switch (status) { + case 0: + return {id:status, statusName:"locate successful."} + case 1: + return {id:status, statusName:"The GNSS scan timed out."} + case 2: + return {id:status, statusName:"The Wi-Fi scan timed out."} + case 3: + return {id:status, statusName:"The Wi-Fi + GNSS scan timed out."} + case 4: + return {id:status, statusName:"The GNSS + Wi-Fi scan timed out."} + case 5: + return {id:status, statusName:"The Bluetooth scan timed out."} + case 6: + return {id:status, statusName:"The Bluetooth + Wi-Fi scan timed out."} + case 7: + return {id:status, statusName:"The Bluetooth + GNSS scan timed out."} + case 8: + return {id:status, statusName:"The Bluetooth + Wi-Fi + GNSS scan timed out."} + case 9: + return {id:status, statusName:"Location Server failed to parse the GNSS location."} + case 10: + return {id:status, statusName:"Location Server failed to parse the Wi-Fi location."} + case 11: + return {id:status, statusName:"Location Server failed to parse the Bluetooth location."} + case 12: + return {id:status, statusName:"Failed to parse location due to the poor accuracy."} + case 13: + return {id:status, statusName:"Time synchronization failed."} + case 14: + return {id:status, statusName:"Failed due to the old Almanac."} + } return getInt(str) } @@ -1526,7 +796,7 @@ function loraWANV2DataFormat (str, divisor = 1) { } }) str2 = parseInt(reverseArr.join(''), 2) + 1 - return '-' + str2 / divisor + return parseFloat('-' + str2 / divisor) } return parseInt(str2, 2) / divisor } @@ -1603,7 +873,6 @@ function getInt (str) { } function getEventStatus (str) { - // return getInt(str) let bitStr = getByteArray(str) let bitArr = [] for (let i = 0; i < bitStr.length; i++) { @@ -3338,13 +2607,13 @@ exports.handler = async (event) => { #### 解码器 -[**SenseCAP T2000 追踪器**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html)是一款工业级 LoRaWAN® 资产追踪器,支持 GNSS、蓝牙和 Wi-Fi 定位,可在室内外环境中提供可靠的追踪功能。它具有 IP67 防护等级,内置 3 轴加速度计用于检测运动状态,以及防拆按钮,当设备被移除时会触发最高优先级警报。T2000-A 和 T2000-B 支持长效电池供电,而太阳能供电的 T2000-C 配备可充电电池,确保持续的户外使用,使该系列产品成为长期免维护资产追踪的理想选择。 +[**SenseCAP T2000 Tracker**](https://www.seeedstudio.com/SenseCAP-Asset-Tracker-T2000-A-p-6580.html),一款工业级 LoRaWAN® 资产追踪器,支持 GNSS、蓝牙和 Wi-Fi 定位,可在室内和室外环境中实现可靠追踪。它具备 IP67 防护等级,内置 3 轴加速度计用于检测运动状态,并配备防拆按钮,当设备被移除时会触发最高优先级报警。T2000-A 和 T2000-B 支持长续航电池供电,而采用太阳能供电并配备可充电电池的 T2000-C 可确保持续的户外使用,使该系列非常适合长期、免维护的资产追踪。

pir


@@ -5529,15 +4798,15 @@ exports.handler = async (event) => { ### Wio Tracker 1110 开发板 -[Wio Tracker 1110 开发板](https://www.seeedstudio.com/Wio-Tracker-1110-Dev-Board-p-5799.html)基于 [Wio-WM1110 无线模块](https://www.seeedstudio.com/Wio-WM1110-Module-LR1110-and-nRF52840-p-5676.html),集成了 [Semtech 的 LR1110](https://www.semtech.com/products/wireless-rf/lora-edge/lr1110) LoRa® 收发器和用于地理定位的多用途射频前端,是一个用户友好的基于 LoRa 的跟踪开发平台。 +[Wio Tracker 1110 Dev Board](https://www.seeedstudio.com/Wio-Tracker-1110-Dev-Board-p-5799.html) 基于 [Wio-WM1110 Wireless Module](https://www.seeedstudio.com/Wio-WM1110-Module-LR1110-and-nRF52840-p-5676.html),集成了 [Semtech's LR1110](https://www.semtech.com/products/wireless-rf/lora-edge/lr1110) LoRa® 收发器和多用途射频前端用于地理定位,是一款用户友好的、基于 LoRa 的追踪开发平台。 -Wio Tracker 1110 开发板具有紧凑的尺寸和丰富的接口,配备了板载天线,便于部署。它支持 Arduino 开发环境和 LoRaWAN 协议栈,非常适合跟踪相关的物联网项目。 +凭借其小巧的尺寸和丰富的接口,Wio Tracker 1110 Dev Board 方便地配备了板载天线,便于部署。它支持 Arduino 开发环境和 LoRaWAN 协议栈,非常适合与追踪相关的物联网项目。

pir

@@ -7468,13 +6737,13 @@ function loraWANV2PositiveDataFormat(str) { ### SenseCAP S210X LoRaWAN 传感器 -[SenseCAP S210X](https://www.seeedstudio.com/catalogsearch/result/?q=s210x) 是一系列无线 LoRaWAN® 传感器。它可以在城市场景中覆盖 2 公里的传输范围,在视距场景中覆盖 10 公里,同时在传输过程中保持较低的功耗。配合可更换电池,支持长达 10 年的使用寿命,以及工业级 IP66 外壳。它支持 -40 ~ 85℃ 的工作温度,可以在恶劣环境中部署。SenseCAP S210X 兼容 LoRaWAN® V1.0.3 协议,可与 LoRaWAN® 网关配合使用。 +[SenseCAP S210X](https://www.seeedstudio.com/catalogsearch/result/?q=s210x) 是一系列无线 LoRaWAN® 传感器。它在城市场景中可覆盖 2km 的传输范围,在视距场景中可覆盖 10km 的传输范围,同时在传输过程中保持较低的功耗。配合可更换电池,可支持长达 10 年的使用寿命,以及工业级 IP66 外壳。它支持 -40 ~ 85℃ 的工作温度,可部署在恶劣环境中。SenseCAP S210X 兼容 LoRaWAN® V1.0.3 协议,并可与 LoRaWAN® 网关配合工作。

pir

@@ -9140,27 +8409,27 @@ exports.handler = async (event) => {
-### SenseCAP S2100 数据记录器 +### SenseCAP S2100 数据记录仪 -[SenseCAP S2100 数据记录器](https://www.seeedstudio.com/SenseCAP-S2100-LoRaWAN-Data-Logger-p-5361.html)是一款多功能设备,可连接 MODBUS-RTU RS485/模拟/GPIO 传感器,轻松将数据传输到 LoRaWAN 网络。凭借其 LoRa 和 IP66 设计,该设备具有令人印象深刻的稳定性和可靠性,能够覆盖长距离传输范围,同时保持超低功耗。它非常适合户外使用,可由电池供电或连接到 12V 外部电源以获得更大的灵活性。当连接到 12V 电源时,可更换的内置电池充当备用电源。此外,S2100 数据记录器针对 OTA 进行了优化,内置蓝牙,使设置和更新快速简单。最重要的是,S2110 转换器使 S2100 数据记录器能够连接到 Grove 传感器,使其成为 DIY 工业级 LoRaWAN 传感器和小规模部署的绝佳选择。 +[SenseCAP S2100 Data Logger](https://www.seeedstudio.com/SenseCAP-S2100-LoRaWAN-Data-Logger-p-5361.html) 是一款多功能设备,可连接 MODBUS-RTU RS485/模拟/ GPIO 传感器,从而轻松将数据传输到 LoRaWAN 网络。凭借其 LoRa 和 IP66 设计,该设备具有出色的稳定性和可靠性,在保持超低功耗的同时还能覆盖较长的传输距离。它非常适合户外使用,可以由电池供电,也可以连接到 12V 外部电源以获得更大的灵活性。连接 12V 电源时,可更换的内置电池将作为备用电源。此外,S2100 数据记录仪内置蓝牙,并针对 OTA 进行了优化,使得设置和更新快速而简单。更重要的是,S2110 转换器使 S2100 数据记录仪能够连接到 Grove 传感器,使其成为 DIY 工业级 LoRaWAN 传感器和小规模部署的绝佳选择。
#### 解码器 - + import Tabs2 from '@theme/Tabs'; import TabItem2 from '@theme/TabItem'; - +
@@ -9781,7 +9050,7 @@ function decodeUplink (input, port) {
- +
@@ -10405,13 +9674,13 @@ function bytes2HexString (arrBytes) { ### SenseCAP S2120 8 合 1 气象传感器 -[SenseCAP S2120 8 合 1 LoRaWAN 气象传感器](https://www.seeedstudio.com/sensecap-s2120-lorawan-8-in-1-weather-sensor-p-5436.html)可测量空气温度、湿度、风速、风向、降雨量、光照强度、紫外线指数和大气压力。它具有超低功耗、可靠性能、内置蓝牙和应用服务,支持 OTA 配置和远程设备管理,实现了低维护成本。它支持多种应用场景,如后院、花园、智慧农业、气象学、智慧城市等。 +[SenseCAP S2120 8-in-1 LoRaWAN Weather Sensor](https://www.seeedstudio.com/sensecap-s2120-lorawan-8-in-1-weather-sensor-p-5436.html) 可测量空气温度、湿度、风速、风向、降雨量、光照强度、UV 指数和气压。凭借超低功耗、可靠性能、内置蓝牙以及用于 OTA 配置和远程设备管理的应用服务,它实现了低维护成本。它支持后院、花园、智慧农业、气象、智慧城市等多种场景应用。

pir

@@ -10423,7 +9692,7 @@ import Tabs3 from '@theme/Tabs'; import TabItem3 from '@theme/TabItem'; - +
@@ -10886,7 +10155,7 @@ function bytes2HexString (arrBytes) {
- +
@@ -11510,13 +10779,13 @@ function Decoder (bytes, port) { ### SenseCAP A1101 - LoRaWAN 视觉 AI 传感器 -[SenseCAP A1101 - LoRaWAN 视觉 AI 传感器](https://www.seeedstudio.com/SenseCAP-A1101-LoRaWAN-Vision-AI-Sensor-p-5367.html) 是一款支持 TinyML 边缘 AI 的智能图像传感器。它支持多种 AI 模型,如图像识别、人员计数、目标检测、仪表识别等。它还支持使用 TensorFlow Lite 训练模型。 +[SenseCAP A1101 - LoRaWAN Vision AI Sensor](https://www.seeedstudio.com/SenseCAP-A1101-LoRaWAN-Vision-AI-Sensor-p-5367.html) 是一款支持 TinyML 边缘 AI 的智能图像传感器。它支持多种 AI 模型,例如图像识别、人数统计、目标检测、仪表识别等。同时也支持使用 TensorFlow Lite 训练模型。
@@ -11528,7 +10797,7 @@ import Tabs4 from '@theme/Tabs'; import TabItem4 from '@theme/TabItem'; - +
@@ -11888,7 +11157,7 @@ function decodeUplink (input) {
- +
@@ -12572,32 +11841,32 @@ function toBinary (arr) { ##### 准备工作 -在配置解码器之前,请根据产品手册正确设置您的传感器和网关,然后连接到您需要的 LoRaWAN 网络服务器。 +在配置解码器之前,请根据产品手册正确设置传感器和网关,然后连接到你所需的 LoRaWAN 网络服务器。 我们以 The Things Stack 为例,请按照以下步骤配置解码器: -##### 配置载荷解码器 +##### 配置 Payload 解码器 -- 导航到您设备的 `Payload Formats` 选项卡。 -- 为 `Payload Format` 选择 `Custom` +- 进入设备的 `Payload Formats` 选项卡。 +- 在 `Payload Format` 中选择 `Custom` - 将 `decoder.js` 的全部内容复制并粘贴到 `decoder` 文本区域。 - 点击 `save payload functions`

pir

-##### 检查解码消息 +##### 检查解码后的消息 -您可以先使用示例载荷测试解码脚本。 +你可以先使用示例 payload 测试解码脚本。 -为此,将原始数据包(如 `01 01 10 98 53 00 00 01 02 10 A8 7A 00 00 AF 51`)复制到 `Payload` 文本输入框中,并根据设备手册选择 `FPort`,然后点击 `Test` 按钮。您将在下方看到成功解析的 JSON 结构。 +为此,将类似 `01 01 10 98 53 00 00 01 02 10 A8 7A 00 00 AF 51` 的原始数据包复制到 `Payload` 文本输入框中,并根据设备手册选择 `FPort`,然后点击 `Test` 按钮。你将在下方看到成功解析的 JSON 结构。

pir

-然后让我们看看脚本的神奇之处。我们导航到 `Live Data` 选项卡,您可以展开任何上传的消息来检查载荷中的 `Event Fields`。这些字段正是由脚本填充的。 +接下来让我们看看脚本的神奇之处。我们进入 `Live Data` 选项卡,你可以展开任意已上传的消息,查看 payload 中的 `Event Fields`。这些字段正是由脚本填充的。

pir

-如果您使用 TTN 的 MQTT Data API 订阅消息,您也将获得解析的 JSON 载荷字段。 +如果你通过 TTN 的 MQTT Data API 订阅消息,你也会获得已解析的 JSON payload 字段。 ```cpp Client mosq-TCSlhYcKaRCn3cIePE received PUBLISH (d0, q0, r0, m0, 'lorawan868/devices/2cf7f12010700041/up', ... (719 bytes)) @@ -12606,4 +11875,4 @@ lorawan868/devices/2cf7f12010700041/up {"app_id":"lorawan868","dev_id":"2cf7f120 ### 资源 -[SenseCAP 解码器](https://github.com/Seeed-Solution/SenseCAP-Decoder) +[SenseCAP Decoder](https://github.com/Seeed-Solution/SenseCAP-Decoder) diff --git a/sites/zh-CN/sidebars.js b/sites/zh-CN/sidebars.js index 6d9dde9ac17b0..9250c5f8356ab 100644 --- a/sites/zh-CN/sidebars.js +++ b/sites/zh-CN/sidebars.js @@ -714,6 +714,8 @@ const sidebars = { label: '用户指南', items: [ 'Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/cn_Quick_Start', + 'Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/cn_Payload_Format', + 'Sensor/SenseCAP/SenseCAP_T2000_Tracker/User_Guide/cn_FAQ', ], }, { diff --git a/sites/zh-CN/static/js/language-switcher.js b/sites/zh-CN/static/js/language-switcher.js index 050a1e1f64544..9c8bd3c479a06 100644 --- a/sites/zh-CN/static/js/language-switcher.js +++ b/sites/zh-CN/static/js/language-switcher.js @@ -1,6 +1,6 @@ // 语言切换器 - 生产环境优化版本 -// 生成时间: 2026-03-11 13:45:57 (北京时间) -// 多语言页面: 2207 个 +// 生成时间: 2026-03-12 17:40:12 (北京时间) +// 多语言页面: 2209 个 (function() { 'use strict'; @@ -13186,6 +13186,16 @@ "es", "ja" ], + "/t2000_faq": [ + "cn", + "es", + "ja" + ], + "/t2000_payload_format": [ + "cn", + "es", + "ja" + ], "/": [ "en", "cn", diff --git a/static/js/language-switcher.js b/static/js/language-switcher.js index 050a1e1f64544..9c8bd3c479a06 100644 --- a/static/js/language-switcher.js +++ b/static/js/language-switcher.js @@ -1,6 +1,6 @@ // 语言切换器 - 生产环境优化版本 -// 生成时间: 2026-03-11 13:45:57 (北京时间) -// 多语言页面: 2207 个 +// 生成时间: 2026-03-12 17:40:12 (北京时间) +// 多语言页面: 2209 个 (function() { 'use strict'; @@ -13186,6 +13186,16 @@ "es", "ja" ], + "/t2000_faq": [ + "cn", + "es", + "ja" + ], + "/t2000_payload_format": [ + "cn", + "es", + "ja" + ], "/": [ "en", "cn",