Kamstrup Meter Protocol

Da vi sidst forlod emnet, havde jeg fået en Kamstrup 382J elmåler, men manglede protokollen for at kunne få andet en IEC1107 informationerne ud af den.

Det problem er løst nu: PyKamstrup er et lille python program der via en seriel-port og et optisk hovede (se tidligere blogindlæg for diagram) kan hente brugbare data ud af ihvertfald min elmåler.

Jeg har prøvet at spørge Kamstrup efter protokol dokumentationen et par gange, men det kommer der ikke noget ud af, selv ikke når man henviser til at Kamstrup selv i deres produktblade beskriver "KMP" protokollen som "the KMP (Kamstrup Meter. Protocol), which is [also] an open protocol."

Vink med Vognstang til Kamstrup:

Det er ikke en "åben protokol" når I ikke vil slippe dokumentationen.

Af hjemmestrikkede protokoller at være er det ikke den værste jeg har set, anvendelsen af CRC16 som checksum trækker opad, den klodsede frame- og escape-mekanisme tæller nedaf.

Jeg har ikke helt styr på hvordan/hvor godt Python virker under Windows, men i hvertfald alle nutidige UNIX dialekter burde kunne bruge ovenstående program.

At implementere protokollen på f.eks Arduino ligger lige til højrebenet.

Samme protokol anvendes tilsyneladende også af mange af Kamstrups andre måleindretninger, men der har man formodentlig andre variabel-numre med andre betydninger.

God Fornøjelse,

phk

PS: Output fra min elmåler:

Energy in (kWh) 6745 Energy out (kWh) 0 Energy in hi-res (kWh) 6745.4191 Energy out hi-res (kWh) 0.0 Voltage p1 (V) 229 Voltage p2 (V) 226 Voltage p3 (V) 232 Current p1 (A) 5.58 Current p2 (A) 1.69 Current p3 (A) 2.36 Power p1 (kW) 1.029 Power p2 (kW) 0.322 Power p3 (kW) 0.438

Poul-Henning Kamps billede
Poul-Henning Kamp
er selvstændig open source-softwareudvikler. Han skriver blandt andet om politik, hysteri, spin, monopoler, frihedskampe gør-det-selv-teknologi og humor.

Kommentarer (94)

Jeg har været igennem det samme for at kunne aflæse mine vand- og varmemålere fra Kamstrup. Har også forsøgt at få protokollen udleveret af Kamstrup, og fik at vide, at det kunne jeg måske godt, hvis mit forsyningsselskab ville tillade det. De svarede forsyningsselskabet aldrig på, så jeg begyndte at lave reverse engineering for at forstå protokollen.

Det letteste er register id'erne. De står i Kamstrup datablade for målerne - så intet problem dér.

Jeg har fundet et par ekstra detaljer, som du ikke har med i din implementation:

Byte 5 fra måleren er enhed jf. følgende:
units = {0: '', 1: 'Wh', 2: 'kWh', 3: 'MWh', 4: 'GWh', 5: 'j', 6: 'kj', 7: 'Mj', 8: 'Gj', 9: 'Cal', 10: 'kCal', 11: 'Mcal', 12: 'Gcal', 13: 'varh', 14: 'kvarh', 15: 'Mvarh', 16: 'Gvarh', 17: 'VAh', 18: 'kVAh', 19: 'MVAh', 20: 'GVAh', 21: 'kW', 22: 'kW', 23: 'MW', 24: 'GW', 25: 'kvar', 26: 'kvar', 27: 'Mvar', 28: 'Gvar', 29: 'VA', 30: 'kVA', 31: 'MVA', 32: 'GVA', 33: 'V', 34: 'A', 35: 'kV',36: 'kA', 37: 'C', 38: 'K', 39: 'l', 40: 'm3', 41: 'l/h', 42: 'm3/h', 43: 'm3xC', 44: 'ton', 45: 'ton/h', 46: 'h', 47: 'hh:mm:ss', 48: 'yy:mm:dd', 49: 'yyyy:mm:dd', 50: 'mm:dd', 51: '', 52: 'bar', 53: 'RTC', 54: 'ASCII', 55: 'm3 x 10', 56: 'ton x 10', 57: 'GJ x 10', 58: 'minutes', 59: 'Bitfield', 60: 's', 61: 'ms', 62: 'days', 63: 'RTC-Q', 64: 'Datetime'}

Byte 6: Antal bytes i data
Byte 7: Skaleringsfaktor:
exponent = b & 0x3F
if(b&0x40):
exponent = -exponent
factor = pow(10, exponent)
if (b&0x80==0x80):
factor=-factor

På Multical-målerne har jeg kørt med seriel parametre: 1200N82 - ved dog ikke om de kan køre hurtigere.

Til gengæld havde jeg ikke helt gennemskuet hvordan escape virkede. Men det kan jeg jo så få med nu :-)

  • 1
  • 0

Jeg er ligeledes igang med at interface til mine Kampstrup målere (min egen 382 bi-måler, mit forsyningsselskabs 601 varme og 61 vand -måler). Jeg har konstrueret et optisk læsehoved via en gammel 741 OpAmp og bortset fra noget echo/crosstalk (som jeg filtrerer i software, gør i også dét?) så fungerer det fint.

Ligeledes har jeg haft kontakt til Kamstrup, og udfordret dem på deres "open protocol" og "open source code" som de skriver i diverse materiale. Anyway, da jeg principielt nægter at acceptere nogen form for NDA, kom jeg ikke længere af den officielle vej. I skal dog næsten lige have denne skønne sætning med, omkring hvorfor protokollen er så hemmelig: "Årsagen hertil er, at vi løbende opdaterer KMP-protokollen og at vi derfor registrerer samtlige "brugere", sådan at vi senere kan rette henvendelse til disse firmaer om f.eks nye funktioner, implementering af nye målertyper osv.". Jeg tror hurtigt vi kan blive enige om at det er fis i en hornlygte, og at den sande grund nok er at Kamstrup forveksler sikkerhed med uigennemskuelighed (klassisk security though obscurity).

Og det giver måske også mening når man ser lidt nærmere på deres protokol, der er f.eks, kun 2^16 mulige passwords (til at kunne omprogrammere måleren) hvilket jeg har brugt til at finde passworded på min 382 måler med, via brute-force - det tager 1½ dag worst case at afprøve samtlige koder, med lidt under et forsøg pr. sekund.

Jeg havde også tænkt mig at dele information og kode med andre, der dog er i C# (Mono) da det er tilstrækkeligt lav-niveau (unsigned byte, serial support mv.) uden at være for besværligt. Grunden til jeg ikke har offentliggjort noget endnu, skyldes uklarhed over ricikoen ved at offentliggøre disse ting.

Det ville være suverent hvis vi kan stikke hovederne sammen og udveksle erfaringer. Et par issues. Hvorfor kalder i det CRC16, når der i virkeligheden er tale om en alm. 8-bit XOR/LRC?

            protected byte[] CalcChecksum(byte[] data)  
    {     
        byte checksum = (byte)0;  
        for (int i = 1; i < data.Length; i+=2)  
        {  
            checksum += (byte)FromKamstrupDouble(data, i);  
        }  
        checksum = (byte)((checksum ^ 0xFF) + 1);  
        return ToKamstrupDouble(checksum);  
    }

Og hvad er det for en mystisk ineffektiv protokol, hvor en Kamstrup byte bliver delt ud på 2 fysiske ASCII bytes der hver indeholder 0x30 - 0x46 og 0x40 hoppes over (speciel karakter)?

    private static byte ToKamstrupByte(int value)  
    {  
        if(value < 10)  
            return (byte)(0x30 + value);  
        return (byte)(0x40 + (value-9));  
    }  

    private static int FromKamstrupByte(byte value)  
    {  
        if(value < 0x3a)  
            return value - 0x30;  
        return value - 0x37;  
    }

Jeg skal lige have ryddet lidt op i koden, så smider jeg det på GitHub. Ser frem til hvad vi kan udrede sammen.

  • 1
  • 0