Skip to content

pdserv-light for Arduino (and compatible)

Type: Enhancement

wouldn't it be cool, if you could use powerful tools like testmanager and DLS for more than industrial applications?

A pdserv light or a msr portation for embedded systems like Arduino would open this door to everyone.

I tries to reverse engineer this, together with chatgpt and wireshark - but failed unfutunately. The Testmanager could not add this as Source.

here was my attempt just for a first try:

#include <ESP8266WiFi.h>
#include <Arduino.h>

const char* ssid = "MSR_ESP_AP";
const char* password = "12345678";
WiFiServer server(2345);
WiFiClient client;

String rxBuffer = "";

void sendData(const String& data) {
  if (client && client.connected()) {
    client.print(data);
    client.flush();
    Serial.print("[SEND] ");
    Serial.print(data);
  }
}

// Optional: Dummywert für Zeit (Double zu Hex, Little Endian)
String doubleToHexLE(double value) {
  union { double f; uint8_t b[8]; } conv;
  conv.f = value;
  char buf[17];
  for (int i = 0; i < 8; ++i)
    sprintf(&buf[i * 2], "%02X", conv.b[i]);
  buf[16] = '\0';
  return String(buf);
}

void setup() {
  Serial.begin(115200);
  delay(500);
  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, password);
  Serial.print("[SETUP] AP-IP: ");
  Serial.println(WiFi.softAPIP());
  server.begin();
  Serial.println("[SETUP] MSR-Server bereit");
}

void loop() {
  static unsigned long lastTime = 0;
  static double curTime = 0;
  if (millis() - lastTime > 1000) {
    curTime = millis() / 1000.0;
    lastTime = millis();
  }

  if (!client || !client.connected()) {
    WiFiClient newClient = server.available();
    if (newClient) {
      client = newClient;
      client.setNoDelay(true);
      rxBuffer = "";
      Serial.println("[SERVER] Neue Verbindung!");
      sendData("<connected name=\"MSR\" host=\"ESP01\" app=\"esp-min\" appversion=\"1.0\" version=\"393226\" features=\"pushparameters,binparameters,eventchannels,statistics,pmtime,aic,messages,polite,list,login,history,xsap,group\" endian=\"little\" recievebufsize=\"8192\" />\n");
    }
    return;
  }

  while (client.available()) {
    char c = client.read();
    rxBuffer += c;
    if (c == '>') {
      Serial.print("[RECV] ");
      Serial.println(rxBuffer);

      // <remote_host ...> -> <ack .../>
      if (rxBuffer.indexOf("<remote_host") != -1) {
        String id = "init";
        int idx = rxBuffer.indexOf("id=\"");
        if (idx > 0) {
          int start = idx + 4;
          int end = rxBuffer.indexOf("\"", start);
          if (end > start) id = rxBuffer.substring(start, end);
        }
        sendData("<ack id=\"" + id + "\" time=\"1753077888.0\" />\n");
      }
      // <list>
      else if (rxBuffer.indexOf("<list>") != -1) {
        sendData("<list><source name=\"ESP01\" host=\"ESP01\" id=\"1\" description=\"MSR ESP\" /></list>\n");
      }
      // <rk> Kanalabfrage
      else if (rxBuffer.indexOf("<rk>") != -1) {
        sendData(
          "<rp id=\"listQ\"><channels>"
          "<channel index=\"0\" name=\"/Time\" datasize=\"8\" typ=\"TDBL\" bufsize=\"40000\" task=\"0\" HZ=\"4000\" />"
          "<channel index=\"1\" name=\"Temp\" datasize=\"2\" typ=\"TINT\" bufsize=\"100\" task=\"0\" HZ=\"1\" />"
          "<channel index=\"2\" name=\"messages\" datasize=\"256\" typ=\"TSTR\" bufsize=\"20\" task=\"0\" HZ=\"1\" />"
          "</channels></rp>\n"
        );
      }
      // <message_history>
      else if (rxBuffer.indexOf("<message_history>") != -1) {
        sendData("<message_history></message_history>\n");
        sendData("<ready />\n");   // Der entscheidende Zusatz!
      }
      // <read ...> Datenabfrage (optional, Beispiel für /Time und Temp)
      else if (rxBuffer.indexOf("<read") != -1) {
        int idx = rxBuffer.indexOf("index=\"");
        int channel = -1;
        if (idx >= 0) {
          int start = idx + 7;
          int end = rxBuffer.indexOf("\"", start);
          if (end > start) channel = rxBuffer.substring(start, end).toInt();
        }
        String out;
        if (channel == 0) {  // /Time
          out = "<data channel=\"0\">" + doubleToHexLE(curTime) + "</data>\n";
        } else if (channel == 1) {  // Temp
          char buf[5];
          int16_t tempValue = 250; // 25,0°C
          sprintf(buf, "%04X", tempValue & 0xFFFF); // 2 Byte Hex, Big Endian
          out = "<data channel=\"1\">" + String(buf) + "</data>\n";
        } else if (channel == 2) { // messages
          out = "<data channel=\"2\"></data>\n";
        } else {
          out = "<data channel=\"" + String(channel) + "\"></data>\n";
        }
        sendData(out);
      }

      rxBuffer = "";
    }
  }
}

There surely is a better way to put this onto an Arduino.