Avläsning av S0 på elmätare via ESP8266

Berätta om dina pågående projekt.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Håller på med avläsning av elmätarens S0-utgång. Gjorde en variant av detta för flera år sedan och tog då in signalen från en fototransistor till serieporten på min dåvarande linuxburk. Funkade hyfsat men inte perfekt pga den simpla lösningen och att avkänningen gjordes via ett enkelt script. Tror det var den här enkla kopplingen jag använde.

http://www.techtrade.se/sv/emc-schematics.asp

Nu när jag lärt mig programmera ESP8266 via Arduino IDE så har jag kört några olika versioner i helgen. Har provat både med en NodeMCU och en Wemos D1 mini. Hårdvaran räcker bra och det är många skojiga utmaningar:

- Att få timingen rätt, så att man får noggrannhet i mätningen.
- Att få robusthet för olika störningar i signalen, störningar från belysning etc.
- Att få ut värdet på lämpligt sätt för vidare användning.

Efter lite labbande valde jag att använda interrupts för att känna av flanken på signalen. I mitt fall är den rejält brusig så jag har fått lägga en hel del tid på att få koden robust. Det kommer rätt många flanker som är "falska" så jag har ett krav på minst 50ms kontinuerlig puls, gissar att elmätaren har 100ms puls men har inte hittat någon uppgift om detta. Har inget oscilloskop. Skulle iofs kunna spela in data och analysera men det har jag inte orkat.

Jag räknar pulser och kan skicka in värdet från vanliga elmätarens display så att man får ut samma plus beräknade medeleffekt mellan två pulser.

I första versionen hämtade jag data via http men drabbades av en brist i ESP8266Wifi-biblioteket som gjorde att den kraschade om man hämtade data oftare än var 5:e sekund. Efter en hel del felsökning (är ovan vid denna typ av hårdvara) så konstaterade jag att det var heapen som krympte för varje klientuppkopplig och även om jag stängde ner från kortet så låg resurserna kvar och skvalpade i minnet ganska länge innan de släpptes. Kom inte på någon annan lösning än att fråga mera sällan. Ska tydligen vara fixat i utvecklingsversionen, där har man maximerat till max 5 samtidiga klienter vad gäller resurser som hålls.

Igår bytte jag till mqtt, första gången jag gjort något med detta. Funkade hyfsat att skicka varje mätvärde, även om de kom tätt, men ibland blev det tokiga värden. Antingen pga programmeringsfel eller för att nätverksuppkopplingarna tar för mycket resurser från mätdelen. Nu skickar jag max ett värde per sekund om något nytt värde finns, funkar bra.

Använder funktionen millis() för att räkna upp cykeltider etc. och den är såvitt jag vet kopplad till hårdvaran så tiderna stämmer bra med verkligheten. Först räknade jag antalet varv med delay(1) och det blev hyfsat OK men efter att ha kört den andra varianten så ser jag att värdena på beräknad medeleffekt mellan två pulser skiljer sig åt 10% åtminstone. Pulsräknandet i sig skiljer sig inte åt.

Någon annan som labbat med detta? Hur har ni gjort? Tycker att det är ett rätt kul projekt med en hel del realtid och annat att trixa med. Det finns säkert en hel del till att finlira med så därför skriver jag här, gillar att trixa med detaljerna.

På bilden ses två generationer. Den första går på Wemos D1 mini och man hämtar data och kan sätta värdet på räknaren via http. Den andra är en NodeMCU som gör motsvarande men via mqtt. Programmen skiljer sig åt ganska mycket eftersom första generationen använder delay(1) för att räkna tid, den andra går via millis(). Bägge läser data från fototransistorn via en vanlig GPIO-port. Lampan som lyser hade jag först till att spegla S0-lysdioden i elmätaren jag ändrade sen till att alternera mellan tänd och släckt efter varje puls eftersom detta blir mycket tydligare än ett kort blink. Borde man kanske ta in signalen via ADC istället? Då kan man ju köra lämpliga filter/signalbehandling för att slippa brus. Går iofs att förbättra den analoga delen också och lägga något filter där. Är bara slumpen vilken hårdvara jag använt till de olika generationerna, bägge kan användas förstås.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Jag kör mosquitto från linuxburken.

mqtt dataström ser ut så här:

Kod: Markera allt

mosquitto_sub -h localhost -t "s0" -v
s0 42357.358/573
s0 42357.359/583
s0 42357.360/595
s0 42357.361/594
s0 42357.362/594
s0 42357.363/589
s0 42357.364/570
s0 42357.365/569
s0 42357.366/558
s0 42357.367/558
s0 42357.368/549
s0 42357.369/536
s0 42357.370/526
Skickar allt i samma sträng, räknare och effekt.

Sätter räknaren så här:

Kod: Markera allt

mosquitto_pub -h localhost -t "s0SetMeter" -m "42354"
Användarvisningsbild
maDa
Inlägg: 4076
Blev medlem: 11 november 2005, 22:13:16
Ort: Malmö
Kontakt:

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av maDa »

Nice :)

MQTT är att föredra tycker jag med
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Har ingen erfarenhet av mqtt och blev lite överraskad av att det var såpass enkelt att sätta upp en message broker via mosquitto. Innan jag provade verkade det vara väldigt jobbigt och abstrakt.

Använde Pubsubclient för mqtt på ESP8266:an, var ganska enkelt att få till.

Ska nog ändra och dela upp i två olika topics, är primärt intresserad av aktuell effekt, den är intressant att skicka i max 1Hz för "realtidsvisning" vid behov.

Själva "elmätarvärdet" (speglat) är ju inte så intressant i sig, kan skickas separat och mer sällan. Vet inte hur man brukar göra, man kan ju också tänka sig att bara skicka vissa värden efter kommando från någon som vill veta, lite slöseri att skicka regelbundet för sådant som sällan är av intresse. Man kan ju rent av skicka mätarvärdet bara då man slår över på nästa hel kWh, eller på begäran.

Ett litet problem är dock att fototransistorn är lite för känslig. Har försökt skärma av men det är svårt att få det tätt, lätt att det blir störningar då jag tänder lampan i rummet där elmätaren finns. Jag ska minska risken lite genom att lägga in en maxgräns för en avläst puls i koden, idag har jag bara en mingräns.

Nuvarande logik är att en puls anses OK mottagen om fototransistorn indikerat "till" under minst X ms (50 just nu) och en flank kommer vid övergången "till"-"från". Om jag ratar övergången om X > något värde, typ 150ms eller liknande så minskar jag risken för falska pulser, å andra sidan missar jag också pulser då om belysningen stör. Givet 1000 pulser/kWh på min mätare gör det ju inte så mycket, desto viktigare är att inte få tokiga värden på momentan effekt. Effektvärdet blir ju iofs aldrig sant eftersom tiden mellan två pulser bara ger vettigt värde om effektuttaget är hyfsat konstant över tiden. Men det duger för normal koll på uttagen effekt.

Jag visar nu aktuellt effektuttag på min Apple Watch, dock med begränsningen att jag bara uppdaterar var 20:e minut i normalfallet, eller på begäran (Apples rekommendationer för "complication" som ingår som en del av visningen på vanliga klockans visning av tid). Kanske ska göra en liten app för realtidsvisning på klockan också, antingen plockar jag värdet från linuxservern, via Dropbox eller möjligen via en mqtt-klient på iPhonen. Har inte forskat i hur lätt det är att få till en mqtt-klient på iPhone men detta vore det allra enklaste. Eller så kör jag ut värdet från linuxservern via http och öppnar upp lämplig port externt så att jag kan sitta på jobbet och kolla effekten hemma i realtid. Bara för att det går... 8)
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Har försökt snygga till koden lite, dock inkonsekvent namngivning och lite fulkodning.

Kanske kan vara av intresse för den som vill göra något liknande med S0, mqtt etc. med ESP8266 eller bara vill hitta fulheter eller buggar i koden.
Sparsamt utprovad efter uppsnyggning...
Kan vara någon miss i datatyper eller onödigt stora typer.

Kod: Markera allt

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <EEPROM.h>

const char* version = "S0_Counter_mqtt 1.3";
const char* date_name = "2016-12-06 Hans Palm";

// Code for detection of S0 power meter signal and delivering data using mqtt 
// Meter value and current effect in watts based on last detected pulses
// Code developed for ESP8266 using either Wemos D1 mini or NodeMCU

// Code adapted for using D1 as input pulled up to HIGH, signal going LOW using phototransistor when signal is detected
// using a circuit similar to http://www.techtrade.se/sv/emc-schematics.asp

// Example use from server side for obtaining data from mqtt broker with data streams receceived:
// mosquitto_sub -h localhost -t "s0" -v
//   s0 42373.226
//   s0 42373.227
//   s0 42373.228
// mosquitto_sub -h localhost -t "watts" -v
//   watts 669
//   watts 665
//   watts 667

// Meter data can be set and saved to EEPROM by the following command (the fraction part is set to 0)
// mosquitto_pub -h localhost -t "s0SetMeter" -m "42373"

// Wifi settings 
const char* ssid = "SSID";
const char* password = "PASSWORD";

// The follwing parameters are only required for fixed IP, otherwise uncomment, also uncomment WiFi.config(ip, gateway, subnet)
//IPAddress ip(192, 168, 0, NNN); 
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0); 

// MQTT server and topic settings
const char* mqtt_server = "192.168.0.xxx";
const char* outTopic_pulse = "s0";
const char* outTopic_effect = "watts";
const char* inTopic = "s0SetMeter";

// S0 settings
const int IMPULSES_PER_KWH = 1000;

// Values used to filter out invalid pulses
const int MINIMUM_S0_PULSE_WIDTH = 50;  // E.g. 50ms for a 100ms pulse
const int MAXIMUM_S0_PULSE_WIDTH = 150; // E.g. 150ms for a 100ms pulse
const int MAX_VALID_EFFECT = 40000;     // Max valid value in effect calculation (W)

// Constant for calculation of current effect in W, based on 1 pulse per second
const int WS_PER_1HZ_IMPULSE = 1000*3600/IMPULSES_PER_KWH;

const unsigned long MAXULONG = 494967295;

const unsigned long MAX_S0_PULSE_INTERVAL = MAXULONG / 2; // Arbitrary large value

// GPIO settings
int ledPin = 2;

// NOTE: Interrupt handling and pinMode setting below assumes pullup to HIGH, LOW input when pulse arrives
int inputPin = D1;

volatile int s0_pulse_length = 0;  //ms
volatile unsigned long time_between_s0_pulses = MAX_S0_PULSE_INTERVAL; //ms

volatile unsigned long s0_counter = 0; //ms
volatile unsigned long watts = 0;
volatile unsigned long meter = 0;

// copy of variables for publishing
volatile unsigned long ps0_counter = 0; //ms
volatile unsigned long pwatts = 0;
volatile unsigned long pmeter = 0;

volatile boolean new_valid_pulse_detected = false;
volatile boolean new_valid_effect_calculated = false;
volatile boolean active_pulse = false;

long time_for_last_pulse_msg = 0; // millis() time when last pulse message was published
long time_for_last_effect_msg = 0; // millis() time when last effect message was published
long before = 0;  // previous millis() time in main loop

WiFiClient espClient;
PubSubClient client(espClient);
 
void setup() {
  
  Serial.begin(115200);
  delay(10);
  Serial.println("setup started ");
 
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);

  read_from_EEPROM();

  pinMode(inputPin,INPUT_PULLUP);
 
  // Connect to WiFi network

  //WiFi.config(ip, gateway, subnet); // Only required for fixed IP
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  attachInterrupt(inputPin, lowInterrupt, FALLING);
}

void read_from_EEPROM() {
  // Read saved meter value from EEPROM
  EEPROM.begin(512);
  EEPROM.get(0, meter);
  EEPROM.end();
  Serial.print("meter vale ");
  Serial.print(meter);
  Serial.println(" read from EEPROM");
}

void save_to_EEPROM() {
  // Save meter value to EEPROM
  Serial.print("meter value ");
  Serial.print(meter);
  Serial.println(" saved in EEPROM");
  EEPROM.begin(512);
  EEPROM.put(0, meter);
  EEPROM.commit();
  EEPROM.end();
}

void start_of_s0_pulse() {
  s0_pulse_length=0;
  active_pulse = true;
}

void end_of_s0_pulse() {
  active_pulse = false;
  
  if ( (s0_pulse_length >= MINIMUM_S0_PULSE_WIDTH) && (s0_pulse_length <= MAXIMUM_S0_PULSE_WIDTH) ) {
    digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle led, indicating detected pulse

    // Valid S0 pulse length, use this S0 pulse measurement
    s0_counter++;
        
    if (s0_counter >= 1000) { // 1000 pulses received, increase kWh meter value
       s0_counter=0;
       meter++;
       save_to_EEPROM();
    }

    pmeter=meter;
    ps0_counter=s0_counter;
    new_valid_pulse_detected = true;
    
    watts = WS_PER_1HZ_IMPULSE*1000/time_between_s0_pulses;

    if ( (watts <= MAX_VALID_EFFECT) && (time_between_s0_pulses != MAX_S0_PULSE_INTERVAL) ) {
        // watts > MAX_VALID_EFFECT indicates too short pulse interval between last detected S0 pulses, thus an invalid pulse interval
        // Also ignore first calulated value when time_between_s0_pulses is initialized to MAX_S0_PULSE_INTERVAL

        // Save last calculated values for publishing later, new measurements can start in parallel
        pwatts=watts;
        new_valid_effect_calculated = true;
    }
  }
  
  time_between_s0_pulses=0;
}

void highInterrupt() {
  // Assuming s0 pulse ends with LOW->HIGH transition
  detachInterrupt(inputPin);
  end_of_s0_pulse(); 
  attachInterrupt(inputPin, lowInterrupt, FALLING);
}

void lowInterrupt() {
  // Assuming s0 pulse begins with HIGH->LOW transition
  detachInterrupt(inputPin);
  start_of_s0_pulse();
  attachInterrupt(inputPin,  highInterrupt, RISING);
}

void callback(char* topic, byte* payload, unsigned int length) {
  // Check incoming message using really ugly code
  String nstring = "";
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    nstring = String (nstring + (char)payload[i]);
  }
  nstring = String (nstring + '\0');
  Serial.println("");
  Serial.print("nstring = ");
  Serial.println(nstring);
  int value;
  if (String(topic + '\0' == inTopic)) {
    value = nstring.toInt(); // (long) 0 is returned if unsuccessful)
    if (value > 0 ) {
      Serial.print("METER value change to ");
      Serial.print(value);
      Serial.println(" requested");
      meter=value;
      s0_counter=0; // Clear S0 counter when resetting meter value
      save_to_EEPROM();   
    }
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266_S0")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      // ... and resubscribe
      client.subscribe(inTopic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}
 
void loop() {
  
  // Check if a client has connected
  if (!client.connected()) {
    reconnect();
  }

  // Perform PubSubClient tasks
  client.loop();

  // Calculate how long time has passed since previous loop execution
  long now = millis();
  long time_elapsed_since_previous_loop = now - before;

  // Increase calculated s0 pulse length and pulse interval based on passed time since previous loop exection
  if (active_pulse) {
    if (s0_pulse_length <= MAXIMUM_S0_PULSE_WIDTH) {
     s0_pulse_length=s0_pulse_length + time_elapsed_since_previous_loop;
    } 
  } else {
    if (time_between_s0_pulses < MAX_S0_PULSE_INTERVAL) {
      time_between_s0_pulses = time_between_s0_pulses + time_elapsed_since_previous_loop;
    }
  }

  // Publish new pulse data but only at a maximum rate of once per second
  if (now - time_for_last_pulse_msg >= 1000) {

    // Check if a new valid pulse has been detected with saved data in "p" variables
    if (new_valid_pulse_detected) {
      char msg[25]; 
      snprintf (msg, 75, "%lu.%lu", pmeter, ps0_counter);
      client.publish(outTopic_pulse, msg);
      new_valid_pulse_detected=false; 
      time_for_last_pulse_msg = now;
    }
  }

  // Publish new effect data but only at a maximum rate of once per second
  if (now - time_for_last_effect_msg >= 1000) {

    // Check if a new valid effect calculation has been made with saved data in "p" variable
    if (new_valid_effect_calculated) {
      char msg[25]; 
      snprintf (msg, 75, "%lu", pwatts);
      client.publish(outTopic_effect, msg);
      new_valid_effect_calculated=false; 
      time_for_last_effect_msg = now;
    }
  }

  before = now;  // Remember current millis() value for next loop execution
  
  delay(1);
}
Senast redigerad av hanpa 8 december 2016, 16:40:17, redigerad totalt 1 gång.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Deklarerade variablerna som används i interrupt handlern som volatile. Inte för att jag märkte något problem utan för att jag är petig. Kanske straffar sig via ökad overhead och risk för fel pga detta men vi får se. Annars fungerar det väldigt bra. Återstår långtidstest för att se om värdet speglar elmätarens värde efter en längre tids körning.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Begränsningen i uppdatering till max en gång per sekund kan tas bort, hade antagligen någon annan brist förut som gjorde att jag valde att begränsa. Drog på en massa effektslukare och det gick fram värden varje gång det blinkar i snabb takt på elmätaren.

Lade dessutom till en egen topic för heapens värde för att kolla att den inte minskade och det gjorde den inte, den ligger konstant på 46696 byte. Faktiskt väldigt smidigt att använda mqtt för detta, lite som att skicka ut på serieporten men den har jag inte inkopplad "live" vid elmätaren. Det är ju bara att prenumerera på en egen topic för detta och skicka den vägen istället!
Videonisse
Inlägg: 15
Blev medlem: 16 juli 2014, 12:17:49

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av Videonisse »

Kul projekt! Har du funderat på att använda Homebridge som brygga för Apples Homekit, då kan man ju göra riktigt kul saker 8)

https://www.npmjs.com/package/homebridge
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Jo jag har funderar på Homebridge men inte kommit till skott. Det är väl iofs då för röststyrningen men jag är samtidigt lite sugen på Amazon Echo eller Google Home. Jag vill ha något som funkar på avstånd. Men å andra sidan kan jag ju köra Siri via Apple Watch också.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Har nu gjort en snabb appskiss för realtidsvisning på Apple Watch. Tar data via http från linuxburken. Kanske gör en mqtt-version senare men den här funkar ju rätt OK. Vet inte om jag har behovet egentligen men nu funkar det i alla fall.

Se videon. Drog på ugnen för att det skulle bli lite action.

https://www.youtube.com/watch?v=yPzzPe1j2vc

Stillbilder, Apple Watch och iPhone. Inte något under av snygg design men de gör jobbet!
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Bra respons måste jag säga. Det är en liten fördröjning på klockan men iPhonen visar i stort sett direkt från live MQTT från sensorn.



Och från kortets detektering, via MQTT till servern, via http till iPhone, mycket liten fördröjning!

Användarvisningsbild
Hedis
Inlägg: 2488
Blev medlem: 8 december 2003, 15:10:44
Ort: Vänersborg
Kontakt:

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av Hedis »

Spännande projekt!
Jag skulle vilja mäta lite förbrukning i en sommarstuga så det här får jag ta och testa. Får pilla ihop lite hårdvara någon dag bara.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Ja den här var riktigt kul. Nu har jag lagt till så att jag provar först med LAN och om jag inte är hemma och kommer i kontakt med WLAN:et så provar jag via mobilnätet/WAN. Trodde det skulle bli betydligt sämre respons men faktum är att jag inte märkte någon skillnad alls. Så jag får realtid även om jag är på bortaplan, givet att jag inte har en för slö uppkoppling till mobilen.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Projektet får anses vara avslutat men jag kommer kanske finlira lite med programvaran etc. En sammanfattning dock för att kanske inspirera andra. Dokumentationen brukar man ju annars slarva med.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Senast redigerad av hanpa 11 december 2016, 21:00:03, redigerad totalt 1 gång.
Användarvisningsbild
hanpa
Utsparkad, på semester
Inlägg: 639
Blev medlem: 22 november 2016, 21:54:43
Ort: Hemort

Re: Avläsning av S0 på elmätare via ESP8266

Inlägg av hanpa »

Färdiga produkten. Ändrade iPhone-appen så att det ser lite mer "tyskt elmätaraktigt" ut. Provade det på klockan också men tyckte att mörk bakgrund gör sig bättre på den skärmen. Bättre realtidsinformation går inte att få. Bara viss eftersläpning till klockan men till iPhone är det inga fördröjningar. Även om man kör hemifrån via 4G så är det i princip realtid, kanske några tiondels sekunder i fördröjning bara.

Skriv svar