====== IR-øje til Kamstrup og andre målere ====== De fleste Kamstrup målere (og visse andre fabrikater) kan aflæses via infrarød kommunikation. Det kræver dog et optisk læseøje, der konverterer lysglimtene til serielt data. Her er beskrivelsen og samlevejledning til sådan et øje. Bemærk: Vi sælger ikke længere kits. {{{{ :projects:kamstrupkitv2.jpg?direct&400|Indhold af kit }}\\ ===== Komponenter ===== * Et printkort ({{{{:projects:kamstrup-schem-v2.pdf|diagram}}), fra http://www.thingiverse.com/thing:264268 * Et plastic-hylster, fra https://www.thingiverse.com/thing:2652216 * 1 x IR-modtager, f.x. http://www.el-supply.dk/?Vnr=455.IRR (klar) * 1 x IR-sender, f.x. http://www.el-supply.dk/?Vnr=455.IRT (sort) * 2 x BC547 * 1 x BC557 * 15 k Ohm modstand (grøn-blå-orange-guld) * 39 k Ohm modstand (orange-hvid-orange-guld) * 2 x 10 k Ohm modstand (brun-sort-sort-rød-brun) * 220 Ohm modstand (rød-rød-brun-guld) * Kabel med 4 ledere, eller 4-pins pinheader * Runde super-magneter, 6 mm * Ø 6 mm, f.x. http://www.supermagnete.de/eng/S-06-06-N Se også projektets [[https://github.com/Hal9k-dk/kamstrup|git]]. ===== Samle-vejledning ===== Det enkeltsidede print er lidt besværligt at lave første gang: Alle komponenter (undtaget de 2 dioder) skal nemlig sidde på BAGSIDEN, hvor print-banerne og lodningerne også er. Dette er et mindre problem med det dobbeltsidede print (som er i vores kit). Layoutet er set fra forsiden (dvs. fra siden uden printbaner): {{{{ :projects:kamstrup-pcb.png?nolink|Layout set forfra }}\\ Opad kan findes ved at der er 4 huller på række. ==== Lod dioderne på forsiden ==== {{ :projects:kamstrup-dioder.jpg?direct&200 }}\\ Transmit skal sidde til venstre, receive til højre (set forfra)\\ {{ :projects:kamstrup-dioder2.jpg?direct&200 }}\\ Bor de 2 midterste huller af hylsteret ud til 5mm, og check at dioderne passer i hullerne:\\ {{ :projects:kamstrup:dsc_0030.jpg?200 }}\\ ==== Lod 39k ohm på mellem de 2 dioder ==== {{ :projects:kamstrup39k.jpg?direct&200 }}\\ ==== Lod de resterende komponenter på ==== Pas meget på at tænke fremad, så du ikke får blokeret for at et andet komponent kan loddes på bagefter. {{ :projects:kamstrupmodstande.jpg?direct&200 }}\\ {{ :projects:kamstrupbc547.jpg?direct&200 }}\\ {{ :projects:kamstrupbc557.jpg?direct&200 }}\\ {{ :projects:kamstrupheader.jpg?direct&200 }} ==== Sæt magneter fast i hylsteret ==== Bor hullerne ud til 6mm, og vær sikker på at bore dem dybt nok til magneterne. Klem en magnet så meget i som muligt, og brug en gummihammer til at slå den helt i:\\ {{ :projects:kamstrup:dsc_0037.jpg?200 }}\\ {{ :projects:kamstrup:dsc_0039.jpg?200 }}\\ {{ :projects:kamstrup:dsc_0040.jpg?200 }}\\ PAS PÅ! Magneter kan nemt splintre, hvis man slår på dem med en metalhammer! ==== Sæt printet i hylsteret, og forbind til Arduino ==== {{:projects:kamstrup:dsc_0042.jpg?200|}} Benene er (fra venstre mod højre): - Receive => Arduino ben 9 - Transmit => Arduino ben 10 - VCC (5V) => Arduino 5V - Ground => Arduino GND Hvis din måler er påtrykt "DLMS" (se billede nedenfor) kan du bruge nedenstående Arduino sketch eller (hvis du forbinder øjet til en PC, Raspberry Pi eller lignende) [[https://github.com/bsdphk/PyKamstrup|PyKamstrup]]. Hvis din måler ikke er mærket DLMS, bruger den formodentlig en anden protokol ved navn IEC 62056 - i dette tilfælde skal der bruges noget andet software, for eksempel [[https://github.com/bsdphk/PyDLMS|PyDLMS]]. Til Kamstrup MULTICAL 66 kan du bruge [[https://github.com/KenanV/KamstrupMultical66|denne software]], som Kenan Vilic har lavet. {{ :projects:kamstrupdlms.jpg?direct&400 |}} Læg Arduino ''SerialKamstrupReadout'' programmet på Arduino'en: #include //Kamstrup setup // Kamstrup 382Jx3 word const kregnums[] = { 0x0001,0x03ff,0x0027,0x041e,0x041f,0x0420 }; char* kregstrings[] = { "Energy in","Current Power","Max Power","Voltage p1","Voltage p2","Voltage p3" }; #define NUMREGS 6 // Number of registers above #define KAMBAUD 9600 // Units char* units[65] = {"","Wh","kWh","MWh","GWh","j","kj","Mj", "Gj","Cal","kCal","Mcal","Gcal","varh","kvarh","Mvarh","Gvarh", "VAh","kVAh","MVAh","GVAh","kW","kW","MW","GW","kvar","kvar","Mvar", "Gvar","VA","kVA","MVA","GVA","V","A","kV","kA","C","K","l","m3", "l/h","m3/h","m3xC","ton","ton/h","h","hh:mm:ss","yy:mm:dd","yyyy:mm:dd", "mm:dd","","bar","RTC","ASCII","m3 x 10","ton xr 10","GJ x 10","minutes","Bitfield", "s","ms","days","RTC-Q","Datetime"}; // Pin definitions #define PIN_KAMSER_RX 9 // Kamstrup IR interface RX #define PIN_KAMSER_TX 10 // Kamstrup IR interface TX #define PIN_LED 13 // Standard Arduino LED // Kamstrup optical IR serial #define KAMTIMEOUT 300 // Kamstrup timeout after transmit SoftwareSerial kamSer(PIN_KAMSER_RX, PIN_KAMSER_TX, false); // Initialize serial void setup () { Serial.begin(57600); pinMode(PIN_LED, OUTPUT); digitalWrite(PIN_LED, 0); // setup kamstrup serial pinMode(PIN_KAMSER_RX,INPUT); pinMode(PIN_KAMSER_TX,OUTPUT); kamSer.begin(KAMBAUD); delay(200); //Serial.println("\n[testKamstrup]"); // poll the Kamstrup registers for data for (int kreg = 0; kreg < NUMREGS; kreg++) { kamReadReg(kreg); delay(100); } } void loop () { // poll the Kamstrup registers for data for (int kreg = 0; kreg < NUMREGS; kreg++) { kamReadReg(kreg); delay(100); } digitalWrite(PIN_LED, digitalRead(PIN_KAMSER_RX)); delay(1000); } // kamReadReg - read a Kamstrup register float kamReadReg(unsigned short kreg) { byte recvmsg[40]; // buffer of bytes to hold the received data float rval; // this will hold the final value // prepare message to send and send it byte sendmsg[] = { 0x3f, 0x10, 0x01, (kregnums[kreg] >> 8), (kregnums[kreg] & 0xff) }; kamSend(sendmsg, 5); // listen if we get an answer unsigned short rxnum = kamReceive(recvmsg); // check if number of received bytes > 0 if(rxnum != 0){ // decode the received message rval = kamDecode(kreg,recvmsg); // print out received value to terminal (debug) Serial.print(kregstrings[kreg]); Serial.print(": "); Serial.print(rval); Serial.print(" "); Serial.println(); return rval; } } // kamSend - send data to Kamstrup meter void kamSend(byte const *msg, int msgsize) { // append checksum bytes to message byte newmsg[msgsize+2]; for (int i = 0; i < msgsize; i++) { newmsg[i] = msg[i]; } newmsg[msgsize++] = 0x00; newmsg[msgsize++] = 0x00; int c = crc_1021(newmsg, msgsize); newmsg[msgsize-2] = (c >> 8); newmsg[msgsize-1] = c & 0xff; // build final transmit message - escape various bytes byte txmsg[20] = { 0x80 }; // prefix int txsize = 1; for (int i = 0; i < msgsize; i++) { if (newmsg[i] == 0x06 or newmsg[i] == 0x0d or newmsg[i] == 0x1b or newmsg[i] == 0x40 or newmsg[i] == 0x80) { txmsg[txsize++] = 0x1b; txmsg[txsize++] = newmsg[i] ^ 0xff; } else { txmsg[txsize++] = newmsg[i]; } } txmsg[txsize++] = 0x0d; // EOF // send to serial interface for (int x = 0; x < txsize; x++) { kamSer.write(txmsg[x]); } } // kamReceive - receive bytes from Kamstrup meter unsigned short kamReceive(byte recvmsg[]) { byte rxdata[50]; // buffer to hold received data unsigned long rxindex = 0; unsigned long starttime = millis(); kamSer.flush(); // flush serial buffer - might contain noise byte r; // loop until EOL received or timeout while(r != 0x0d){ // handle rx timeout if(millis()-starttime > KAMTIMEOUT) { Serial.println("Timed out listening for data"); return 0; } // handle incoming data if (kamSer.available()) { // receive byte r = kamSer.read(); if(r != 0x40) { // don't append if we see the start marker // append data rxdata[rxindex] = r; rxindex++; } } } // remove escape markers from received data unsigned short j = 0; for (unsigned short i = 0; i < rxindex -1; i++) { if (rxdata[i] == 0x1b) { byte v = rxdata[i+1] ^ 0xff; if (v != 0x06 and v != 0x0d and v != 0x1b and v != 0x40 and v != 0x80){ Serial.print("Missing escape "); Serial.println(v,HEX); } recvmsg[j] = v; i++; // skip } else { recvmsg[j] = rxdata[i]; } j++; } // check CRC if (crc_1021(recvmsg,j)) { Serial.println("CRC error: "); return 0; } return j; } // kamDecode - decodes received data float kamDecode(unsigned short const kreg, byte const *msg) { // skip if message is not valid if (msg[0] != 0x3f or msg[1] != 0x10) { return false; } if (msg[2] != (kregnums[kreg] >> 8) or msg[3] != (kregnums[kreg] & 0xff)) { return false; } // decode the mantissa long x = 0; for (int i = 0; i < msg[5]; i++) { x <<= 8; x |= msg[i + 7]; } // decode the exponent int i = msg[6] & 0x3f; if (msg[6] & 0x40) { i = -i; }; float ifl = pow(10,i); if (msg[6] & 0x80) { ifl = -ifl; } // return final value return (float )(x * ifl); } // crc_1021 - calculate crc16 long crc_1021(byte const *inmsg, unsigned int len){ long creg = 0x0000; for(unsigned int i = 0; i < len; i++) { int mask = 0x80; while(mask > 0) { creg <<= 1; if (inmsg[i] & mask){ creg |= 1; } mask>>=1; if (creg & 0x10000) { creg &= 0xffff; creg ^= 0x1021; } } } return creg; } Flere kode eksempler er at finde på github [[https://github.com/Hal9k-dk/kamstrup/tree/master/Software%20eksempler|her]] ===== Test ===== Hvis alt er samlet rigtigt virker IR-øjet nu. Det er dog en god ide at lave et par tests, da det er nemt at lave fejl. ==== Transmit test ==== Den første test er at transmit øjet blinker. Find en mobil-telefon og brug dens kamera til at kigge på transmit øjet, mens Arduino'en kører. Nogle digital-kameraer kan se infrarødt lys -vi har fået at vide at nogle mobiler, f.eks. iPhone 6 og Samsung Galaxy 4, **ikke** kan se infrarødt lys (men for iPhone er det tilsyneladende sådan, at frontkameraet **kan** se infrarødt lys, mens kameraet på bagsiden ikke kan). Så det kan være nødvendigt at prøve mere end en - find evt. en fjernbetjening og kontrollér at du kan se signalet fra den med dit kamera. Den skulle gerne blinke i en lilla farve:\\ {{:projects:kamstrup:dsc_0047.jpg?200|}} Hvis det ikke virker er der en fejl på printet. Check alt igennem igen, og check for kortslutninger mellem baner --- også under komponenter! ==== Receive test ==== På Arduino'en sidder der en LED på ben 13. Test-programmet lyser med LED på ben 13 hvis IR-recieveren er i mørke, og slukker hvis IR-receiveren er i lys. Lys på IR-receiveren. LED på Arduino ben 13 skal slukke, indenfor 2 sekunder. Hvis det ikke virker er der en fejl på printet. Check alt igennem igen, og check for kortslutninger mellem baner --- også under komponenter! ==== Kamstrup test ==== Sæt læseøjet fast på Kamstrup måleren. På Arduino seriel konsollen (som skal sættes til 57600 baud) burde der komme data:\\ {{:projects:kamstrup:dsc_0056.jpg?200|}} Hvis der i stedet står ''Timed out listening for data'' er der ikke forbindelse. Prøv at dreje IR-hovedet 180 grader. Hvis det ikke virker, så drej det langsomt hele vejen rundt. Hvis der stadig ikke er forbindelse: Lav de to forrige tests, check alt igennem, specielt for kortslutninger! Bemærk: På nogle målere aktiveres IR-forbindelsen af de magneter der sidder på plasthuset. Så hvis du tester uden, kan du risikere at du ikke får noget signal. ==== Alternativ hus ==== Hvis man vil bruge en esp8266 til at aflæse sin måler med kan man i stedet printe dette [[https://www.thingiverse.com/thing:4437840|hus]] hvor espen sidder lige over øjet. ===== Målere ===== ^ Navn ^ Model ^ Status ^ Noter ^ | Kamstrup | 685-392-OK-40 | Begrænset output | https://github.com/anderskvist/PyDLMS | | Kamstrup | Multical 402 | Fungerer | https://github.com/Hal9k-dk/kamstrup/tree/master/Software%20eksempler/kamstrup_multical402 | | Kamstrup | Multical 21 | Ingen output | Det lader til at den ikke tænder for ir porten. | | Kamstrup | 382Lx7 (684-38B-L4-73-010) | Fungerer | https://github.com/Hal9k-dk/kamstrup/tree/master/Software%20eksempler/kamstrup_powermeter \\ https://github.com/bipsendk/kamstrup-382Lx7 |