Open main menu

Landis+Gyr GridStream Protocol

Revision as of 16:18, 6 March 2021 by Hash (talk | contribs) (→‎Data)

Protocol Analysis

Analysis and decoding of the packets used on the Landis+Gyr GridStream mesh network.

Packet Structure

Sync and Header


The sync word that the Landis+Gyr smart meters send is shown below, this can be used in GNU Radio or other tools to receive only packets transmitted by the meters. Note that at the start of the header we begin using start and stop bits. These must be stripped off of the rest of the data packet during processing.

Sync and Header
Sync Header
0xAA 0xAA 0xAA 0xAA 0xAA 0xA 0x00 0xFF 0x2A
10101010 10101010 10101010 10101010 10101010 1010 0 00000000 1 0 11111111 1 0 00101010 1

Using GNU Radio it was found that shortening the Sync requirements a bit and incorporating part of the header leads to the cleanest data for further downstream processing. The modified sync shown in 8 bit chunks is shown below.

Sync Word used with GNURadio
0xAA 0xAA 0xAA 0xAA 0xA0 0x05 0xFF
10101010 10101010 10101010 10101010 10100000 00000101 11111111

The final byte of the sync (0x2A) along with it's start and stop bits are discarded as part of the processing.



Type, Length and Sub Type


So far only two types of packets have been observed, a 0x55 and a 0xD5 packet. Multiple lengths and SubTypes of these are listed below.

Type SubType Length Packets Purpose
1 0x55 0x30 0x0023 Report up-time and other unknown data
2 0x55 0x30 0x0028
3 0xD5 0x21 0x0016
4 0xD5 0x21 0x0017
5 0xD5 0x29 0x0016
6 0xD5 0x29 0x0017
7 0xD5 0x51 0x0047
8 0xD5 0xC0 0x00FD




Data


Data varies per packet type but a common theme is the 0x55 packets appear to be broadcasts from the meters with only their own ID. 0xD5 packets usually contain two ID's and appear to be how data is routed across the network. Sometimes one of the meter ID's in a 0xD5 packet is FFFFFFFF which may be a broadcast packet. This was observed when packets were sent that appear to be updating the system time of the meters.



Checksum


C++ source code below used to calculate the CRC, different energy providers use a different initial CRC value. Assume this is to segment traffic, unsure if Routers/Collectors are shared by different providers to return traffic or not.

uint16_t Landis_crc16 (uint16_t crc, const std::vector<uint8_t> &data, size_t size) { 
// CoServ CRC = 0x45F8 
// Oncor CRC = 0x5FD6 
// Hard coded Poly 0x1021
    uint16_t i = 0;
    while (size--) {
        crc ^= data[i] << 8; 
        i++; 
        for (unsigned k = 0; k < 8; k++) 
            crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
    }
    return crc; 
}

Captured Meter Data

There have been two packet types observed thus far, a 0x55 and a 0xD5 packet.

  • 0x55 appears to be broadcasts from the meters and happen frequently. They have been observed multiple times per minute from a single meter.
  • 0xD5 appears to be a packet for transporting data across the mesh network. Each D5 packet will contain two meter ID's, Meter ID #1 and Meter ID #2. There are many 0xD5 packet length and types that have been observed, some are shown below.

0x55 Meter Data

The data below was captured from the same meter (F0EE36DB) and shows some of the values that can change with each transmission. Different meters have different fixed data and some of the data changes less frequently as well.

0x55 Captured packets from Meter F0EE36DB (Oncor)
Pkt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Not part of CRC calc Data
Header Type Length SubType Unknown Unknown Unknown Unknown Counter Uptime Unknown Meter ID Unknown Unknown Unknown Unknown CRC Trailing
1 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 0C 0001ECBF A483 F0EE36DB 0100 213204 384F 7E80 0896 04
2 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 16 0001ECC6 A483 F0EE36DB 0100 213204 3AC5 7E80 F47E 04
3 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 2A 0001ED05 A483 F0EE36DB 0100 213204 1207 7E80 A412 04
4 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 34 0001ED29 A483 F0EE36DB 0100 213204 1FF9 7E80 D9C4 04
5 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 38 0001ED37 A483 F0EE36DB 0100 213204 2571 7E80 963C 04
6 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 42 0001ED5C A483 F0EE36DB 0100 213204 33A9 7E80 8384 04
7 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 4C 0001ED60 A483 F0EE36DB 0100 213204 354D 7E80 2CB6 04
8 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 4E 0001ED79 A483 F0EE36DB 0100 213204 3F25 7E80 871A 04
9 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 60 0001EDA6 A483 F0EE36DB 0100 213204 0F05 7E80 25C9 04
10 00FF2A 55 0023 30 FFFFFFFFFFFF 50 CF8DD9E2 C0 6A 0001EDCD A483 F0EE36DB 0100 213204 1E55 7E80 F33F 04

Commentary on the data fields above, they have been grouped based on sample analysis but this could be wrong. If you see a new pattern not noticed before you may be correct.

  • Field 5 - Never observed a packet with this length and subtype that wasn't all FF's
  • Field 6 - Have only seen this change when comparing data from different energy providers
  • Field 7 - Appears to either be location identifier (Oncor) or duplicate meter ID (Coserv)
  • Field 9 - Increments some amount with each transmission and rolls over at 0xFF
  • Field 10 - Value in seconds since meter powered on, easy way to see last time the meter experienced a power outage.
  • Field 15 - This value counts from near 0 to around 3FFF and rolls over, not sure what it is. Have not been able to correlate the counting value or speed vs time to any sort of power utilization.
0x55 Captured packets from Meter 5021D005 (Coserv)
Pkt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Not part of CRC calc Data
Header Type Length SubType Unknown Unknown Meter ID Unknown Counter Uptime Unknown Meter ID Unknown Unknown Unknown Unknown CRC Trailing
1 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 7C 0003FB20 A403 5021D005 0100 072001 1E56 7E00 9032 04
2 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 AE 0003FB9E A403 5021D005 0100 072001 0DA8 7E00 83E8 04
3 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 B8 0003FBC1 A403 5021D005 0100 072001 1B54 7E00 2924 04
4 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 C0 0003FC30 A403 5021D005 0100 072001 052E 7E00 09FC 04
5 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 EA 0003FC9F A403 5021D005 0100 072001 3062 7E00 C69A 04
Power restored after an outage
1 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 06 0000000F A403 5021D005 01EA 6000FE 26DA 7E30 90CE 04
2 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 0E 0000000F A403 5021D005 01EA 6000FE 26EF 7E10 2740 04
3 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 20 00000011 A403 5021D005 01EA 6000FE 2801 7E90 8B23 04
4 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 2C 00000013 A403 5021D005 01EA 6000FE 2883 7E60 1A1A 04
5 00FF2A 55 0023 30 FFFFFFFFFFFF FE 5021D005 00 54 00000017 A403 5021D005 01EA 6000FE 2A72 7E80 E3CD 04

0xD5 Meter Data

There appear to be multiple packet lengths and styles for the 0xD5 packet. Some samples shown below.

0xD5 Captured packet
Pkt 1 2 3 4 5 6 7 8 9 10 11 12
Not part of CRC calc Data
Header Type Length SubType Meter ID #1 Meter ID #2 Unknown Unknown Unknown Unknown CRC Trailing
1 00FF2A D5 0016 21 F05FCB84 F0FC4DB1 E288 0100 273205 00781930 CB72 00


00FF2A D5 0016 21 F073B577 F062363D FA88 0100 1F6C04 14E93E70 CF80 04

00FF2A D5 0017 29 8073AEAC F0F28D56 1288 0100 1F3204 041CBB1930 2D2A 04

00FF2A D5 001B 21 F10679E2 8073CE7D F498 0100 106C02 0A15F9055F06571A80 37C5 00

00FF2A D5 001C 29 8073ADB3 8073CE7D 9088 0100 106C02 040A99CF055F3A4B1170 A696 04

00FF2A D5 0021 22 F05A1A60 8073CE7D D8010100106C020520301D81800A99CF055F3ADD1410 A560 04

00FF2A D5 0047 51 F05A4BCC F03D4CD7 5A6032F37F0001DA2E00022BE9 A483 010150D075D9E2E0 F03D4CD7 000103240403030806080801000000036EE8001F6C0401E9203020818018C22930 9294 00