Skip to content
This repository was archived by the owner on Apr 14, 2023. It is now read-only.

Binary Protocol

Brian Rudy edited this page Mar 9, 2022 · 7 revisions

The binary protocol is used by connecting to TCP port 6001 on uscv2.naviensmartcontrol.com.

Request Types

  1. Initial Connection Request
  2. State Request
  3. Device Control Request
  4. Trend Sample Request
  5. Trend Monthly Request
  6. Trend Yearly Request

Response Types

  1. Channel Information Response
  2. State Response
  3. Device Control Response
  4. Trend Sample Response
  5. Trend Monthly Response
  6. Trend Yearly Response

Initial Connection Request

Upon initial connection, a request containing the authenticated username $iPhone1.0$ and deviceID (a.k.a GID in the requestDevicelist REST API response) must be sent. Unlike the remaining binary API requests and responses, the initial request itself must be encoded in ASCII.

Example

00000000  75 73 65 72 6e 61 6d 65  24 69 50 68 6f 6e 65 31    username$iPhone1
00000010  2e 30 24 31 32 33 34 35  36 37 38 39 31 32 33 34    .0$1234567891234
00000020  35 36 37                                            567

Channel Information Response

Upon successfully submission of the Initial Connection Request, the binary protocol will respond with a Channel Information Response such as the following

Example

00000000  XX XX XX XX XX XX XX XX  01 01 0e 00 04 01 00 00
00000010  01 00 00 00 00 00 01 00  00 02 02 00 00 01 00 00
00000020  00 00 00 01 00 00 02 03  01 01 02 62 b6 20 20 03
00000030  01 00 00 01

Common Response Header

Of this, the first 12 bytes are the Common Response Header consisting of the following

deviceID

Description: An 8 byte unique ID used in all requests and responses. The first 6 bytes are the NaviLink's MAC address
Example: 01 02 03 04 05 06 07 08 (Denoted as XX XX XX XX XX XX XX XX in the sample capture above)

countryCD

Description: A one byte country code designation
Example: 01

controlType

Description: A one byte ID identifying the message type (as specified in the ControlType enum)
Example: 01 corresponding with the ControlType.CHANNEL_INFOMATION enum

swVersionMajor

Description: A one byte value of the software version major number Example: 0e = 14 dec

swVersionMinor

Description: A one byte value of the software version minor number Example: 00 = 0 dec

The rest of the Channel Information Response starts at array position 12 (byte 13)

channelUse = 04 matched to enum CHANNEL_3_USE and set to ChannelUse.CHANNEL_3_USE (NPE device is connected to NaviLink serial port 3)
computed firmware version = swVersionMajor * 100 + swVersionMinor = 1400 dec since this is < 1500, b1 = 13 (otherwise b1 = 15)
loops 3 times (index 0-2), one loop per channel (13 bytes per channel)
01 00 00 01 00 00 00 00 00 01 00 00 02 
-channel.channel = 01
-channel.deviceSorting = 00 matched to enum NO_DEVICE and set to DeviceSorting.NO_DEVICE
-channel.deviceCount = 00
-channel.deviceTempFlag = 01 matched to enum CELSIUS and set to TemperatureType.CELSIUS
-channel.mininumSettingWaterTemperature = 00 & 0xFF = 0
-channel.maxinumSettingWaterTemperature = 00 & 0xFF = 0
-channel.heatingMininumSettingWaterTemperature = 00 & 0xFF = 0
-channel.heatingMaxinumSettingWaterTemperature = 00 & 0xFF = 0
-channel.useOnDemand = 00 matched to enum UNKNOWN and set to OnDemandFlag.UNKNOWN
-channel.heatingControl = 01 matched to enum SUPPLY and set to HeatingControl.SUPPLY
-channel.wwsdFlag = 00 wwsdFlag is a bitfield. For bits in byte: 76543210 -> 0 is boolean matched to enum OK and set to WWSDFlag.OK
-channel.commercialLock derived from wwsdFlag bitfield value (For bits in byte: 76543210 -> 1 is commercialLock), 0 matched to enum OK and set to CommercialLockFlag.OK
-channel.hotwaterPossibility derived from wwsdFlag bitfield value (For bits in byte: 76543210 -> 2 is hotwaterPossibility),  0 matched to enum OFF and set to NFBWaterFlag.OFF
-channel.recirculationPossibility derived from wwsdFlag bitfield value (For bits in byte: 76543210 -> 3 is recirculationPossibility), matched to enum OFF and set to RecirculationFlag.OFF
-channel.useWarmWater = 02 matched to enum OFF and set to OnOFFFlag.OFF 
-would also read two more bytes for channel.mininumSettingRecirculationTemperature and channel.maxinumSettingRecirculationTemperature if the computed firmware version is >1500, but the app does not properly evaluate this condition (bug)
02 00 00 01 00 00 00 00 00 01 00 00 02
03 01 01 02 62 b6 20 20 03 01 00 00 01
-channel.channel = 03
-channel.deviceSorting = 01 matched to enum NPE and set to DeviceSorting.NPE
-channel.deviceCount = 01
-channel.deviceTempFlag = 02 matched to enum FAHRENHEIT and set to TemperatureType.FAHRENHEIT
-channel.mininumSettingWaterTemperature = 62 & 0xFF = 98 dec
-channel.maxinumSettingWaterTemperature = b6 & 0xFF = 182 dec
-channel.heatingMininumSettingWaterTemperature = 20 & 0xFF = 32 dec (probably a default value as this feature is not in use)
-channel.heatingMaxinumSettingWaterTemperature = 20 & 0xFF = 32 dec (probably a default value as this feature is not in use)
-channel.useOnDemand = 03 matched to enum WARMUP and set to OnDemandFlag.WARMUP
-channel.heatingControl = 01 matched to enum SUPPLY and set to HeatingControl.SUPPLY
-channel.wwsdFlag = 00 wwsdFlag is a bitfield. For bits in byte: 76543210 -> 0 is boolean matched to enum OK and set to WWSDFlag.OK
-channel.commercialLock derived from wwsdFlag bitfield value (For bits in byte: 76543210 -> 1 is commercialLock), 0 matched to enum OK and set to CommercialLockFlag.OK
-channel.hotwaterPossibility derived from wwsdFlag bitfield value (For bits in byte: 76543210 -> 2 is hotwaterPossibility),  0 matched to enum OFF and set to NFBWaterFlag.OFF
-channel.recirculationPossibility derived from wwsdFlag bitfield value (For bits in byte: 76543210 -> 3 is recirculationPossibility), matched to enum OFF and set to RecirculationFlag.OFF
-channel.highTemperature = 00 matched to enum TEMPERATURE_60 and set to HighTemperature.TEMPERATURE_60
-channel.useWarmWater = 01 matched to enum ON OnOFFFlag.ON
-would also read two more bytes for channel.mininumSettingRecirculationTemperature and channel.maxinumSettingRecirculationTemperature if the computed firmware version is >1500, but the app does not properly evaluate this condition (bug)

State Request

Example

00000000  07 99 00 a6 37 00 XX XX  XX XX XX XX XX XX 01 03
00000010  01 01 02 00 00 00 00 00  00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00
All requests share a hardcoded 6 byte prefix that contains the following:
07 99 00 a6 37 00
-stx = 07
-did = 99
-reserve = 00
-cmd = a6
-dataLength = 37
-dSid = 00
device ID = XX XX XX XX XX XX XX XX

Rest of status request follows starting at array position 14 (byte 15):
commandCount = 01
currentControlChannel = 03 (NPE device is connected to Navilink serial port 3)
deviceNumber = 01 (first device on the serial bus)
controlSorting = 01  (1 for deviceInfo requests, and 2 for deviceControlWeekly and deviceControl)
infoItem = 02 matched to enum STATE and set to ControlType.STATE (This field is only used when info is requested as per this request)
controlItem = 00 matched to enum UNKNOWN and set to ControlType.UNKNOWN (This field is only used when controlling)
controlValue = 00 (this is set to 0 for info requests, 1 for setting weekly schedule info or another value when controlling)
controlValue_WeeklyDay = 00
controlValue_WeeklyCount = 00
controlValue_WeeklyDay_1_Hour = 00
controlValue_WeeklyDay_1_Minute = 00
controlValue_WeeklyDay_1_Flag = 00
controlValue_WeeklyDay_2_Hour = 00
controlValue_WeeklyDay_2_Minute = 00
controlValue_WeeklyDay_2_Flag = 00
controlValue_WeeklyDay_3_Hour = 00
controlValue_WeeklyDay_3_Minute = 00
controlValue_WeeklyDay_3_Flag = 00
controlValue_WeeklyDay_4_Hour = 00
controlValue_WeeklyDay_4_Minute = 00
controlValue_WeeklyDay_4_Flag = 00
controlValue_WeeklyDay_5_Hour = 00
controlValue_WeeklyDay_5_Minute = 00
controlValue_WeeklyDay_5_Flag = 00
controlValue_WeeklyDay_6_Hour = 00
controlValue_WeeklyDay_6_Minute = 00
controlValue_WeeklyDay_6_Flag = 00
controlValue_WeeklyDay_7_Hour = 00
controlValue_WeeklyDay_7_Minute = 00
controlValue_WeeklyDay_7_Flag = 00
controlValue_WeeklyDay_8_Hour = 00
controlValue_WeeklyDay_8_Minute = 00
controlValue_WeeklyDay_8_Flag = 00
controlValue_WeeklyDay_9_Hour = 00
controlValue_WeeklyDay_9_Minute = 00
controlValue_WeeklyDay_9_Flag = 00
controlValue_WeeklyDay_10_Hour = 00
controlValue_WeeklyDay_10_Minute = 00
controlValue_WeeklyDay_10_Flag = 00

State Response

Example

00000000  XX XX XX XX XX XX XX XX  01 02 0e 00 13 05 1c 00
00000010  01 01 03 01 00 00 01 2f  b3 22 c7 40 00 00 7d 7b
00000020  2b 00 3b 00 20 20 01 02  02 02 00 01 00 00 00 00
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000040  00 00 00 00 00 00 00 00  00 00 00 02 00 00 00 00
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000060  00 00 00 00 00 00 00 00  00 00 00 03 00 00 00 00
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000080  00 00 00 00 00 00 00 00  00 00 00 04 00 00 00 00
00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000000A0  00 00 00 00 00 00 00 00  00 00 00 05 00 00 00 00
000000B0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000000C0  00 00 00 00 00 00 00 00  00 00 00 06 00 00 00 00
000000D0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000000E0  00 00 00 00 00 00 00 00  00 00 00 07 00 00 00 00
000000F0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000100  00 00 00 00 00 00 00 00  00 00 00 20 20 20 20
Common response header:
deviceID = XX XX XX XX XX XX XX XX
countryCD = 01
controlType = 02 matched to enum STATE and set to ControlType.STATE
swVersionMajor = 0e & 0xFF = 14 dec
swVersionMinor = 00 & 0xFF = 0

Status response details start at array position 12 (byte 13):
controllerVersion = 13 05
pannelVersion = 1c 00
deviceSorting = 01 matched to enum NPE and set to DeviceSorting.NPE
deviceCount = 01 Corresponds with the number of devices on serial bus (if more than 1 => cascaded devices)
currentChannel = 03 (device is connected to serial port 3 on the Navilink)
deviceNumber = 01 Corresponds with this device's address on the serial bus
errorCD = (00 & 0xFF) + (00 & 0xFF) * 256 = 0
operationDeviceNumber = 01 This changes to 0 when the unit is not actively running. This is also used to compute stats for cascaded devices
AverageCalorimeter = 2f & 0xFF = 2F (47 dec, this is converted in the app by 47 / 2 = 23.5 %)
gasInstantUse = (b3 & 0xFF) + (22 & 0xFF) * 256 = 0xB3 + (0x22 * 256) = 179 + 8704 = 8883 (This is converted from kilocalories in the app by 8883 * 3.968 = 35,247.744 and rounded to 35,247.7 BTU. If converted accurately, should actually be 35,227.02 BTU)
gasAccumulatedUse = c7 40 00 00 treat as little endian and convert to int = 16583 (This is converted from m^3/10 in the app by 16583 * 35.314667 / 10.0 = 58,562.3122861 and rounded to 58562.3 ft^3)
hotWaterSettingTemperature = 7d & 0xFF = 125 (F)
hotWaterCurrentTemperature = 7b & 0xFF = 123 (F)
hotWaterFlowRate = (2b & 0xFF) + (00 & 0xFF) * 256 = 43 + 0 =  43 (This is converted from LPM/10 in the app by 43 / 3.785 / 10.0 = 1.1360 and rounded to 1.1 GPM. If converted accurately is 1.13594 GPM, but with rounding it wouldn't matter)
hotWaterTemperature = 3b & 0xFF = 59 (F, this is actually the inlet temperature per the app)
heatSettingTemperature = 00 & 0xFF = 0
currentWorkingFluidTemperature = 20 & 0xFF = 32 dec (probably a default value when not using external recirc)
currentReturnWaterTemperature = 20 & 0xFF = 32 dec (probably a default value when not using external recirc)
powerStatus = 01 matched to enum ON and set to OnOFFFlag.ON
heatStatus = 02 matched to enum OFF and set to OnOFFFlag.OFF
useOnDemand = 02 matched to enum OFF and set to OnOFFFlag.OFF
weeklyControl = 02 matched to enum OFF and set to OnOFFFlag.OFF
totalDaySequence = 00
Loops 7 times (0-6), one for each day of week contained in the status response
-matches day.daySequence to enums defined in KDWeekly.DayOfWeek based on values 01-07 in binary data
-for array position 43 (byte 44) = 01:
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
--weeklyTotalCount = 00 (loops again from 0 to day.weeklyTotalCount max of 10 on/off times per day of week)
---reads 3 byte sets of hour, minute and OnOFFFlag enum
00 00 00 
00 00 00 
00 00 00 
00 00 00 
00 00 00 
00 00 00 
00 00 00 
00 00 00 
00 00 00 
00 00 00
hotWaterAverageTemperature = 20 & 0xFF = 32 dec (probably a default value when not using external recirc)
inletAverageTemperature = 20 & 0xFF = 32 dec (probably a default value when not using external recirc)
supplyAverageTemperature = 20 & 0xFF = 32 dec (probably a default value when not using external recirc)
returnAverageTemperature = 20 & 0xFF = 32 dec (probably a default value when not using external recirc)

Would read an additional two bytes for recirculationSettingTemperature and recirculationCurrentTemperature if recirculation was enabled (the status response would be two bytes larger)

Device Control Request

Example: Turning Off Power

00000000  07 99 00 a6 37 00 XX XX  XX XX XX XX XX XX 01 03
00000010  01 02 00 01 02 00 00 00  00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00
Rest of status request follows starting at array position 14 (byte 15):
commandCount = 01
currentControlChannel = 03 (NPE device is connected to Navilink serial port 3)
deviceNumber = 01 (first device on the serial bus)
controlSorting = 02 (1 for deviceInfo requests, and 2 for deviceControlWeekly and deviceControl)
infoItem = 00 (this field is set to 0 when controlling)
controlItem = 01 matched to enum POWER
controlValue = 02 This corresponds with enum OnOFFFlag.OFF

Example: Turn on Power

00000000  07 99 00 a6 37 00 XX XX  XX XX XX XX XX XX 01 03
00000010  01 02 00 01 01 00 00 00  00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00
Rest of status request follows starting at array position 14 (byte 15):
commandCount = 01
currentControlChannel = 03 (NPE device is connected to Navilink serial port 3)
deviceNumber = 01 (first device on the serial bus)
controlSorting = 02 (1 for deviceInfo requests, and 2 for deviceControlWeekly and deviceControl)
infoItem = 00 (this field is set to 0 when controlling)
controlItem = 01 matched to enum POWER
controlValue = 01 This corresponds with enum OnOFFFlag.ON

Example: Setting temperature to 120

00000000  07 99 00 a6 37 00 XX XX  XX XX XX XX XX XX 01 03
00000010  01 02 00 03 78 00 00 00  00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00
Rest of status request follows starting at array position 14 (byte 15):
commandCount = 01
currentControlChannel = 03 (NPE device is connected to Navilink serial port 3)
deviceNumber = 01 (first device on the serial bus)
controlSorting = 02 (deviceControl)
infoItem = 00 (this field is set to 0 when controlling)
controlItem = 03 matched to enum WATER_TEMPERATURE
controlValue = 78 (120 dec)

Example: Adding two weekly schedule entries for Sunday at 01:10 and 02:00 both for off

00000000  07 99 00 a6 37 00 XX XX  XX XX XX XX XX XX 01 03
00000010  01 02 00 06 01 01 02 01  0a 02 02 00 02 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00
Rest of status request follows starting at array position 14 (byte 15):
commandCount = 01
currentControlChannel = 03 (NPE device is connected to Navilink serial port 3)
deviceNumber = 01 (first device on the serial bus)
controlSorting = 02 (deviceControl)
infoItem = 00 (this field is set to 0 when controlling)
controlItem = 06 matched to enum DeviceControl.WEEKLY
controlValue = 01 matched to enum OnOFFFlag.ON
controlValue_WeeklyDay = 01 corresponds with enum DayOfWeek.SUN
controlValue_WeeklyCount = 02 (total of 2 entries)
controlValue_WeeklyDay_1_Hour = 01 (1AM 24H time)
controlValue_WeeklyDay_1_Minute = 0a (10 dec => 01:10)
controlValue_WeeklyDay_1_Flag = 02 corresponds with enum OnOFFFlag.OFF
controlValue_WeeklyDay_2_Hour = 02 (2AM 24H time)
controlValue_WeeklyDay_2_Minute = 00 (0 dec => 02:00)
controlValue_WeeklyDay_2_Flag = 02 corresponds with enum OnOFFFlag.OFF
controlValue_WeeklyDay_3_Hour = 00
controlValue_WeeklyDay_3_Minute = 00
controlValue_WeeklyDay_3_Flag = 00
controlValue_WeeklyDay_4_Hour = 00
controlValue_WeeklyDay_4_Minute = 00
controlValue_WeeklyDay_4_Flag = 00
controlValue_WeeklyDay_5_Hour = 00
controlValue_WeeklyDay_5_Minute = 00
controlValue_WeeklyDay_5_Flag = 00
controlValue_WeeklyDay_6_Hour = 00
controlValue_WeeklyDay_6_Minute = 00
controlValue_WeeklyDay_6_Flag = 00
controlValue_WeeklyDay_7_Hour = 00
controlValue_WeeklyDay_7_Minute = 00
controlValue_WeeklyDay_7_Flag = 00
controlValue_WeeklyDay_8_Hour = 00
controlValue_WeeklyDay_8_Minute = 00
controlValue_WeeklyDay_8_Flag = 00
controlValue_WeeklyDay_9_Hour = 00
controlValue_WeeklyDay_9_Minute = 00
controlValue_WeeklyDay_9_Flag = 00
controlValue_WeeklyDay_10_Hour = 00
controlValue_WeeklyDay_10_Minute = 00
controlValue_WeeklyDay_10_Flag = 00

Device Control Response

Upon receiving a properly formed Device Control Request, the protocol will respond with a State Response showing the updated state.

Trend Sample Request

Example

00000000  07 99 00 a6 37 00 XX XX  XX XX XX XX XX XX 01 03
00000010  01 01 03 00 00 00 00 00  00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00
Rest of status request follows starting at array position 14 (byte 15):
commandCount = 01
currentControlChannel = 03 (NPE device is connected to Navilink serial port 3)
deviceNumber = 01 (first device on the serial bus)
controlSorting = 01 (deviceInfo)
infoItem = 03 matched to ControlType.TREND_SAMPLE
controlItem = 00
controlValue = 00

Trend Sample Response

Example

00000000  XX XX XX XX XX XX XX XX  01 03 0e 00 13 05 1c 00
00000010  01 01 03 01 00 00 00 e8  05 00 00 f7 40 00 00 3b
00000020  3a 42 00 00 00 00 00
Common response header:
deviceID = XX XX XX XX XX XX XX XX
countryCD = 01
controlType = 03 matched to enum ControlType.TREND_SAMPLE
swVersionMajor = 0e & 0xFF = 14 dec
swVersionMinor = 00 & 0xFF = 0

The app does not use the following (status-like) response details starting at array position 12 (byte 13):
controllerVersion = 13 05
pannelVersion = 1c 00
deviceSorting = 01 matched to enum NPE and set to DeviceSorting.NPE
deviceCount = 01
currentChannel = 03 (device is connected to serial port 3 on the Navilink)
deviceNumber = 01

Trend sample information response starts at array position 20 (byte 21):
modelInfo = 00 00 00
totalOperatedTime = e8 05 00 00 treat as little endian and convert to int = 1512 (hour)
totalGasAccumulateSum = f7 40 00 00 treat as little endian and convert to int = 16631 (this is not displayed, but likely corresponds with gasAccumulatedUse used in the state response and would be converted from m^3/10 in the app by 16631 * 35.314667 / 10.0 = 58,731.8226877 and rounded to 58,731.8 ft^3)
totalHotWaterAccumulateSum = 3b 3a 42 00 treat as little endian and convert to int (this is not displayed)
totalCHOperatedTime = 00 00 00 00 (heating is not used)
if the response payload was >39, would read another four bytes for totalDHWUsageTime

Trend Monthly Request

Example

00000000  07 99 00 a6 37 00 XX XX  XX XX XX XX XX XX 01 03
00000010  01 01 04 00 00 00 00 00  00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00
Rest of status request follows starting at array position 14 (byte 15):
commandCount = 01
currentControlChannel = 03 (NPE device is connected to Navilink serial port 3)
deviceNumber = 01 (first device on the serial bus)
controlSorting = 01 (deviceInfo)
infoItem = 04 matched to ControlType.TREND_MONTH
controlItem = 00
controlValue = 00

Trend Monthly Response

Example

00000000  XX XX XX XX XX XX XX XX  01 04 0e 00 13 05 1c 00
00000010  01 01 03 01 1f 01 00 00  00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 02 00 00 00 00
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000040  00 03 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000050  00 00 00 00 00 00 00 04  00 00 00 00 00 00 00 00
00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000080  00 00 00 06 00 00 00 00  00 00 00 00 00 00 00 00
00000090  00 00 00 00 00 00 00 00  00 07 00 00 00 00 00 00
000000A0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 08
000000B0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000000C0  00 00 00 00 00 09 00 00  00 00 00 00 00 00 00 00
000000D0  00 00 00 00 00 00 00 00  00 00 00 0a 00 00 00 00
000000E0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000000F0  00 0b 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000100  00 00 00 00 00 00 00 0c  00 00 00 00 00 00 00 00
00000110  00 00 00 00 00 00 00 00  00 00 00 00 00 0d 00 00
00000120  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000130  00 00 00 0e 00 00 00 00  00 00 00 00 00 00 00 00
00000140  00 00 00 00 00 00 00 00  00 0f 00 00 00 01 00 00
00000150  00 00 00 00 00 02 00 00  00 00 00 20 20 00 00 10
00000160  00 00 00 09 00 00 00 00  00 00 00 06 00 00 00 00
00000170  00 20 20 00 00 11 00 00  00 05 00 00 00 6c 09 00
00000180  00 04 00 00 00 00 00 20  20 01 00 12 00 00 00 08
00000190  00 00 00 00 00 00 00 05  00 00 00 00 00 20 20 00
000001A0  00 13 00 00 00 17 00 00  00 69 12 00 00 09 00 00
000001B0  00 00 00 20 20 02 00 14  00 00 00 0b 00 00 00 27
000001C0  09 00 00 0c 00 00 00 00  00 20 20 01 00 15 00 00
000001D0  00 04 00 00 00 d4 08 00  00 04 00 00 00 00 00 20
000001E0  20 01 00 16 00 00 00 00  00 00 00 00 00 00 00 00
000001F0  00 00 00 00 00 00 00 00  00 17 00 00 00 00 00 00
00000200  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 18
00000210  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000220  00 00 00 00 00 19 00 00  00 00 00 00 00 00 00 00
00000230  00 00 00 00 00 00 00 00  00 00 00 1a 00 00 00 00
00000240  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000250  00 1b 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000260  00 00 00 00 00 00 00 1c  00 00 00 00 00 00 00 00
00000270  00 00 00 00 00 00 00 00  00 00 00 00 00 1d 00 00
00000280  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000290  00 00 00 1e 00 00 00 00  00 00 00 00 00 00 00 00
000002A0  00 00 00 00 00 00 00 00  00 1f 00 00 00 00 00 00
000002B0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00
Common response header:
deviceID = XX XX XX XX XX XX XX XX
countryCD = 01
controlType = 04 matched to enum ControlType.TREND_MONTH
swVersionMajor = 0e & 0xFF = 14 dec
swVersionMinor = 00 & 0xFF = 0

The app does not use the following (status-like) response details starting at array position 12 (byte 13):
controllerVersion = 13 05
pannelVersion = 1c 00
deviceSorting = 01 matched to enum NPE and set to DeviceSorting.NPE
deviceCount = 01
currentChannel = 03 (device is connected to serial port 3 on the Navilink)
deviceNumber = 01

Trend month information response starts at array position 20 (byte 21):
totalDaySequence = 1f = 31 dec
Loops 31 times and reads the following
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-trendData.sequence = 01
-trendData.modelInfo = 00 00 00
-trendData.gasAccumulatedUse = 00 00 00 00 treat as little endian and convert to int = 0 converted from m^3/10 in the app by 0 * 35.314667 / 10.0 = 0 and rounded to 0 ft^3
-trendData.hotWaterAccumulatedUse = 00 00 00 00 treat as little endian and convert to int = 0 (not shown in the app for NPE, but for others that do this is converted in the app by 0 / 3.785 / 10.0 = 0 and rounded to 0 G)
-trendData.hotWaterOperatedCount = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
-trendData.onDemandUseCount = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
-trendData.heatAccumulatedUse = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
-trendData.outdoorAirMaxTemperature = 00
-trendData.outdoorAirMinTemperature = 00
-trendData.dHWAccumulatedUse = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
...
14 00 00 00 0b 00 00 00 27 09 00 00 0c 00 00 00 00 00 20 20 01 00
-trendData.sequence = 14
-trendData.modelInfo = 00 00 00
-trendData.gasAccumulatedUse = 0b 00 00 00 treat as little endian and convert to int = 11 converted from m^3/10 in the app by 11 * 35.314667 / 10.0 = 38.8461337 and rounded to 38.9 ft^3
-trendData.hotWaterAccumulatedUse = 27 09 00 00 treat as little endian and convert to int = 2343 (not shown in the app for NPE, but for others that do this is converted in the app by 2343 / 3.785 / 10.0 = 61.902246 and rounded to 61.9 G)
-trendData.hotWaterOperatedCount = 0c 00 => ((0c & 0xFF) + (00 & 0xFF) * 256 = 12 dec converted in the app by 12 * 10 = 120
-trendData.onDemandUseCount = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
-trendData.heatAccumulatedUse = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 00 dec
-trendData.outdoorAirMaxTemperature = 20 = 32 dec (probably a default value as this feature is not in use)
-trendData.outdoorAirMinTemperature = 20 = 32 dec (probably a default value as this feature is not in use)
-trendData.dHWAccumulatedUse = 01 00 => ((01 & 0xFF) + (00 & 0xFF) * 256 = 1 dec

Trend Yearly Request

Example

00000000  07 99 00 a6 37 00 XX XX  XX XX XX XX XX XX 01 03
00000010  01 01 05 00 00 00 00 00  00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000030  00 00 00 00 00 
Rest of status request follows starting at array position 14 (byte 15):
commandCount = 01
currentControlChannel = 03 (NPE device is connected to Navilink serial port 3)
deviceNumber = 01 (first device on the serial bus)
controlSorting = 01 (deviceInfo)
infoItem = 05 matched to ControlType.TREND_YEAR
controlItem = 00
controlValue = 00

Trend Yearly Response

Example

00000000  XX XX XX XX XX XX XX XX  01 05 0e 00 13 05 1c 00
00000010  01 01 03 01 18 01 00 00  00 00 00 00 00 00 00 00
00000020  00 00 00 00 00 00 00 00  00 00 00 02 00 00 00 00
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000040  00 03 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000050  00 00 00 00 00 00 00 04  00 00 00 00 00 00 00 00
00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 05 00 00
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000080  00 00 00 06 00 00 00 00  00 00 00 00 00 00 00 00
00000090  00 00 00 00 00 00 00 00  00 07 00 00 00 00 00 00
000000A0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 08
000000B0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000000C0  00 00 00 00 00 09 00 00  00 00 00 00 00 00 00 00
000000D0  00 00 00 00 00 00 00 00  00 00 00 0a 00 00 00 00
000000E0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000000F0  00 0b 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000100  00 00 00 00 00 00 00 0c  00 00 00 00 00 00 00 00
00000110  00 00 00 00 00 00 00 00  00 00 00 00 00 0d 00 00
00000120  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000130  00 00 00 0e 00 00 00 00  00 00 00 00 00 00 00 00
00000140  00 00 00 00 00 00 00 00  00 0f 00 00 00 00 00 00
00000150  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 10
00000160  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000170  00 00 00 00 00 11 00 00  00 00 00 00 00 00 00 00
00000180  00 00 00 00 00 00 00 00  00 00 00 12 00 00 00 00
00000190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000001A0  00 13 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000001B0  00 00 00 00 00 00 00 14  00 00 00 00 00 00 00 00
000001C0  00 00 00 00 00 00 00 00  00 00 00 00 00 15 00 00
000001D0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
000001E0  00 00 00 16 00 00 00 00  00 00 00 00 00 00 00 00
000001F0  00 00 00 00 00 00 00 00  00 17 00 00 00 00 00 00
00000200  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 18
00000210  00 00 00 45 00 00 00 d0  2d 00 00 2f 00 00 00 00
00000220  00 20 20 05 00
Common response header:
deviceID = XX XX XX XX XX XX XX XX
countryCD = 01
controlType = 05 matched to enum ControlType.TREND_YEAR
swVersionMajor = 0e & 0xFF = 14 dec
swVersionMinor = 00 & 0xFF = 0

The app does not use the following (status-like) response details starting at array position 12 (byte 13):
controllerVersion = 13 05
pannelVersion = 1c 00
deviceSorting = 01 matched to enum NPE and set to DeviceSorting.NPE
deviceCount = 01
currentChannel = 03 (device is connected to serial port 3 on the Navilink)
deviceNumber = 01

Trend year information response starts at array position 20 (byte 21):
totalDaySequence = 18 = 24 dec (rolling month by month over two years. Last sequence is most recent)
Loops 24 times and reads 22 bytes
01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-trendData.sequence = 01 (1 dec)
-trendData.modelInfo = 00 00 00
-trendData.gasAccumulatedUse = 00 00 00 00 treat as little endian and convert to int = 0 converted from m^3/10 in the app by 0 * 35.314667 / 10.0 = 0 and rounded to 0 ft^3
-trendData.hotWaterAccumulatedUse = 00 00 00 00 treat as little endian and convert to int = 0 (not shown in the app for NPE, but for others that do this is converted in the app by 0 / 3.785 / 10.0 = 0 and rounded to 0 G)
-trendData.hotWaterOperatedCount = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
-trendData.onDemandUseCount = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
-trendData.heatAccumulatedUse = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
-trendData.outdoorAirMaxTemperature = 00 & 0xFF
-trendData.outdoorAirMinTemperature = 00 & 0xFF
-trendData.dHWAccumulatedUse = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
...
18 00 00 00 45 00 00 00 d0 2d 00 00 2f 00 00 00 00 00 20 20 05 00
-trendData.sequence = 18 (24 dec)
-trendData.modelInfo = 00 00 00
-trendData.gasAccumulatedUse = 45 00 00 00 treat as little endian and convert to int = 69 converted from m^3/10 in the app by 69 * 35.314667 / 10.0 = 243.6712023 and rounded to 243.7 ft^3
-trendData.hotWaterAccumulatedUse = d0 2d 00 00 treat as little endian and convert to int = 11728 (not shown in the app for NPE, but for others that do this is converted in the app by 11728 / 3.785 / 10.0 = 309.854689 and rounded to 309.9 G)
-trendData.hotWaterOperatedCount = 2f 00 => ((2f & 0xFF) + (00 & 0xFF) * 256 = 47 dec converted in the app by 47 * 10 = 470
-trendData.onDemandUseCount = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
-trendData.heatAccumulatedUse = 00 00 => ((00 & 0xFF) + (00 & 0xFF) * 256 = 0 dec
-trendData.outdoorAirMaxTemperature = 20 & 0xFF = 32 dec (probably a default value as this feature is not in use)
-trendData.outdoorAirMinTemperature = 20 & 0xFF = 32 dec (probably a default value as this feature is not in use)
-trendData.dHWAccumulatedUse = 05 00 => ((05 & 0xFF) + (00 & 0xFF) * 256 = 5 dec (hours)