Das sprechende Multimeter - Teil 5 - AZ-Delivery

Our TDMM has in the last four blog posts (Part 1, Part 2, Part 3, Part 4) learned a lot. Today we want to bring the TDMM into the net. We have a nice display in the device and we can also have measurement results. Often, however, you don't just want to carry out a measurement once, but also save measurements that are later evaluated or look at the values ​​on the mobile phone.

The TDMM on the net

There are some options on how to display data from the TDMM on a web client, on a laptop, a mobile phone, or another device. Let's consider two variants here:

Representation of the data on a website

Our D1 mini can be used as a web server. It represents the measured values ​​on a website to which the user logs on with his mobile phone, tablet or PC, for example.

This solution is quite easy to realize with various libraries. The display can be made graphically,  For example, by representing measuring instruments, or the measured value course as a graphic.

A disadvantage of this version: The data is shown on the website, but not saved for later use. Some effort is necessary to create a website that looks really good on the various end devices.

Depending on the task, this option is more or less useful. There is another way:

MQTT - a little more effort - some advantages

In the professional environment you will first Transfer the data and then take care of their presentation. The interesting protocol MQTT offers such an option, which many of them certainly already know from other applications - it is often used.

The basic concept looks like this:

MQTT is built around a "broker", the news receives
and distributed. Well -known systems are Mosquitto or Eclipse.

Messages are published for a "topic" that is hierarchically built.
A topic is with us TDMM/voltage. If the TDMM for it
The MQTT broker passes on this value to all clients that have subscribed to the topic. The “publish” instruction is used to publish. For the subscription of a topic, the client uses the "Subscribe" function.

The TDMM sends the data to the broker as long as it is logged in there. It does not check whether the value has also arrived there and whether it was taken over by the clients. At MQTT, however, the QOS (Quality of Service) can be defined individually, depending on how reliable the data transmission should be. We use the simplest version QOS = 0 ("Send and Forget").

There are excellent descriptions of MQTT with all the details of this protocol. The project's website provides information:
mqtt.org This may be a lot for the beginning. I would like to get from the websites in German blog.doubleslash.de call that seems recommended to me. Also Wikipedia delivers useful information.

MQTT on the TDMM

MQTT allows you to transfer the data from the TDMM to a web -enabled device and to display it in the most diverse way. Instead of programming a representation for your end device with Java and other tools, with a MQTT tool, they also represent the results. I present three examples to you here:   Representation of TDMM data on a mobile phone   Representation in Home Assistant, which becomes a "Lab Assistant"   Takeover of the TDMM data by a Python script Before we read MQTT data, two tasks must be done:   Setting up the MQTT broker   Sketch of the TDMM so expand that it is logged in at the broker and sends data For the first task, I refer to the many instructions online. My MQTT broker is part of the local home assistant installation and ran after a few mouse clicks. But the setup of a broker "From the Scratch" is also not rocket science. In the following we assume that a MQTT broker is available.

Now the somewhat more demanding task remains: expand the sketch of the TDMM. It grows on almost 300 lines. In order to make the code better readable, it was partially new with functions like Current () structured.


// TDMM - The Talking Digital Multimeter - German Speaking DMM
// Michael Klein & Bernd Schaedler 2024
//  
// Thanks to rob.tillaart for: ads1x15.h
// Thanks to Gerald Lechner for: Talking_Display.H
// Based on Wemos D1 Mini V3 - Use Board Manager Lolin (Wemos) D1 Mini Pro
#include <ESP8266WIFI.h> // wifi lib
#include <Pub.h> // mqtt lib
#include <Ads1x15.h>
#include <U8G2Lib.h>
#include <Software.h>
#include <Talking_Display.h>
#define Dfplayer_rx 12 // RX connection for communication with the DFPlayer 
#define Dfplayer_tx 13 // TX connection for communication with the DFPlayer 
#define Busy 14 // D5 Busy Head of the DFPlayer

const char* SSID = "Name of the network";
const char* password = "My WLAN password";
const char* mqtt_server = "192.168.0.112";

Ipaddress local_ip(192, 168, 0, 50); // Set Static IP Address
Ipaddress subnet(255, 255, 255, 0);
Ipaddress gateway(192, 168, 0, 1); // Set your gateway ip address

Wificlient Espclient;
Pub client(Espclient);
long load = 0;

Software SS(Dfplayer_rx,Dfplayer_tx); // rx, tx
Talking_Display<Software> TD(SS,Busy);

U8g2_sh1106_128x64_noname_f_hw_i2c U8G2(U8G2_R0, /* reset =*/U8x8_pin_none); u8g2_uint_t offset;
u8g2_uint_t Width; 
int32_t VAL_00 =0; int32_t VAL_01 =0; int32_t VAL_02=0; int32_t VAL_03=0;
float dcurrent = 0; float dcurrenty=0; String dcurrentx = ""; float mid = 2.344;
int32_t VRES_00 =0; int32_t VRES_01 =0; float resval=0; float Resvolts_01 =0;

Bool Stated0 = digital read(16); Bool Stated3 = digital read(0); 
Bool Stated4 = digital read(2); 
 
Ads1115 Ads(0x48);

void set up() {
Serial.Begin(19200);

setup_wifi(); 
client.set server(mqtt_server, 1883);

TD.Begin();
  SS.set(2000);
  TD.set volume(27);
  Serial.print("Speech output ready");
  TD.setlish(false);
  TD.setwordtimeout(2); 
  TD.tab(Tderror);

pin mode(16,Input); // D0 for "Speak" key 
pin mode(2, Input_pullup); // D3 for "Say-Ampere" Switch
pin mode(0, Input_pullup); // D4 for "Say-Volt" Switch
pin mode(15, OUTPUT); // D8 for relay

Serial.print(__File__);
Serial.print("Ads1x15_lib_version:"); Serial.print(Ads1x15_lib_version);

Wire.Begin(); // D1 Mini V3 Connect SDA> D2 (PIN 4) SCL> D1 (pin 5)
Ads.Begin();

  IF (!Ads.Begin()) {
      Serial.print("Address ads1115 or 0x48 not found");
    }
    IF (!Ads.Isconnected()) {
      Serial.print("Address 0x48 not found");  
    }
  Serial.print("AD1115 is Properly Connected.");
  
  U8G2.Begin();
  U8G2.enableutf8print();
  start screen(); // call for initial screen  

  current();
  IF (dcurrent < 0.00){
    Serial.print("Calibration in Progress");
    while (dcurrent<0.00) {
      mid=mid - 0.001;
      delay(100);
      current(); Serial.print(mid); Serial.print("  "); Serial.print(dcurrent);
    }
  }
  IF (dcurrent > 0.00){
    Serial.print("Calibration in Progress");
    while (dcurrent>0.00) {
      mid=mid + 0.001;
      delay(100);
      current(); 
      Serial.print(mid); Serial.print("  "); Serial.print(dcurrent);
    }
  }
} // end of setup

void loop() {

  IF (!client.connected()) { // If the connection breaks off, realignment
  Serial.print("I'm in the reconnect loop");delay(1000);
  reconnect();
  }
  client.loop();

  Ads.setgain(0);
  VAL_01=0;
  for (intimately X=0; X<10; X++){ // Measure Voltage
    VAL_00 = Ads.readadc_Differential_0_1();  
    VAL_01=VAL_01+VAL_00;
    delay(2); // Delay 2ms
  }
  VAL_01=VAL_01/10; // Mean Value of Voltage
  float volts_01 = Ads.tovoltage(VAL_01)*22.87; // multiplier 
  String voltsstring = String(volts_01);
  Serial.print("U:"); Serial.print(voltsstring); Serial.print("Volt");
  client.publish("MQTTUSER/TDMM/tension", String(volts_01).C_STR());
  
  current(); // Current Measurement Subroutine

  Serial.print("\ t"); Serial.print("I:"); Serial.print(String(dcurrent)); Serial.print("A");
  client.publish("MQTTUSER/TDMM/electricity", String(dcurrent).C_STR());
  client.publish("MQTTUSER/TDMM/performance", String(ABS(dcurrent*volts_01)).C_STR()); 
  client.publish("MQTTUSER/TDMM/resistance", String(resval).C_STR());
  
  U8G2.clear buffer(); // Show value on oled 
  U8G2.set font(u8g2_font_ncenb12_tf);
  U8G2.setcursor(0, 20);
  U8G2.print("U:");U8G2.print(voltsstring);U8G2.print("V");
  U8G2.setcursor(3, 35);
  U8G2.print("I:");U8G2.print(dcurrent);U8G2.print("A");
  U8G2.setcursor(2, 50);
  U8G2.print("P:");U8G2.print(ABS(dcurrent*volts_01));U8G2.print("W");
  U8G2.buffle();
  Serial.print("\ t"); Serial.print("P:"); Serial.print(ABS(dcurrent*volts_01));Serial.print("W");
  
  Stated0=digital read(16); Stated3=digital read(2); Stated4=digital read(0); 
  IF (Stated0 == Low && Stated3 == Low) { 
    Serial.print("Volts Speaking Activated");// volt- & speak-key pressed?
    TD.Sayfloat(volts_01,2);
    delay(1500);
    TD.game(363);
  } 
  IF (Stated0 == Low && Stated4 == Low) {  // amp- & speak-key pressed?
    Serial.print("Ampere Speaking Activated");
    delay(1000);
    TD.Sayfloat(dcurrent,2);
    delay(1500);
    TD.game(364);
  }
  Stated0 = HIGH; // set state back to high
  
  IF (analogead(0)>400){ // "Resistor-Switch set?"
    resistor();
    }
  TD.loop();
  delay(1500);
  
} // end of loop

void start screen() {
  U8G2.clear buffer(); 
  U8G2.set font(u8g2_font_ncenb08_tr); // set fontsize
  U8G2.setfontpostop(); // set position
  const char* title = "-TDMM-";
  const char* subtitle = "Art-of-Electronics.Blog";
  intimately Xtitle = (128 - U8G2.Dutf8width(title)) / 2; // Title position + center
  intimately ytitle = 10; // vertical position of title
  intimately Xsubitle = (128 - U8G2.Dutf8width(subtitle)) / 2; // Subtitle + center
  intimately Ysubitle = 40; // subtitle vertical position
  U8G2.setdrawcolor(1); // TextColor (1 = white)
  U8G2.Drawstr(Xtitle, ytitle, title);
  U8G2.Drawstr(Xsubitle, Ysubitle, subtitle);
  U8G2.buffle(); // Send display data
  TD.game(362); // start tune
  delay(3500);
}

void current(){
  VAL_02=0; dcurrent=0; dcurrenty=0; // Measure Current
  for (intimately y=0; y<10; y++){
    VAL_02 = Ads.readadc(2); 
    float volts_02 = Ads.tovoltage(VAL_02);  
    dcurrenty = (volts_02 - mid)*5.6482; // Multiplier for 0.185 MV/A
    dcurrent=dcurrent+dcurrenty; 
  }
  dcurrent=dcurrent/10; // Mean Value of Current
  String dcurrentx = String(dcurrent);
}

void resistor() {
  float mesres=470;
  VRES_01 = Ads.readadc(3); 
  Resvolts_01 = Ads.tovoltage(VRES_01);
  IF (Resvolts_01 >= 3.2) {
	    Ads.setgain(0); digital(15, HIGH); mesres=4700; delay(500);
	    }
	    Else IF (Resvolts_01 < 3.2 && Resvolts_01 >= 1.37) {
	    Ads.setgain(1); 
	    }
	    Else IF (Resvolts_01 < 1.37 && Resvolts_01 >= 0.68) {
	    Ads.setgain(2); 
      }
      Else IF (Resvolts_01 < 0.68 && Resvolts_01 >= 0.34) {
	    Ads.setgain(4); 
      }
      Else IF (Resvolts_01 < 0.34 && Resvolts_01 >= 0.17) {
	    Ads.setgain(8); 
      }
	    Else {
	    Ads.setgain(16);
	    }
  VRES_01=0; Resvolts_01=0; float voltsum=0;
  for (intimately X=0; X<10; X++){ // Measure Voltage at Divider
    VRES_01 = Ads.readadc(3);  
    Resvolts_01 = Ads.tovoltage(VRES_01);
    voltsum=voltsum+Resvolts_01;
    delay(2); // Delay 2ms
  }
  Resvolts_01=voltsum/10; // Mean Value of Voltage
  resval= Resvolts_01*mesres/(3.32-Resvolts_01);
  IF (resval <0){
    resval=999999;
  }
  digital(15, Low); // relay off
  String ohmstring = String(resval);
  U8G2.set font(U8G2_FONT_CU12_T_SYMBOLS);
  U8G2.setcursor(0, 0);
  U8G2.print("R:");U8G2.print(ohmstring);
  U8G2.print("\ U2126");
  U8G2.buffle();
  U8G2.set font(u8g2_font_ncenb12_tf);
  Serial.print("R:"); Serial.print(intimately(resval)); Serial.print("Ohm");
  IF (digital read(16) == Low){
    TD.Sayint(intimately(resval)); 
    delay(1000);
    TD.game(365);
  }
}

void Tderror(String MSG) {
  Serial.print(MSG);
}

void setup_wifi() {

  // Configures Static IP Address
  IF (!Wifi.config(local_ip, gateway, subnet)) {
    Serial.print("Static IP Failed to Configure");
           }

  delay(10);
  // WE Start by Connecting to a WiFi Network
  Serial.print("Hello - here is the TDMM");
  Serial.print();
  Serial.print("Connecting to");
  Serial.print(SSID);
  Wifi.Begin(SSID, password);

  while (Wifi.status() != Wl_connected) 
  {
    delay(500);
    Serial.print(".");
  }
  Serial.print(""); 
  Serial.print("WiFi Connected");
  Serial.print("IP address:");
  Serial.print(Wifi.localip());
}

void reconnect() {
  // loop unstil we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT Connection ...");
    // Attempt to Connect
    //if(client.connect("mqttuser ")) {
    IF (client.connect("HomeSistant20","MQTTUSER","Mein_MQtt_Passwort")) {
    Serial.print("Connected");
    } 
    Else {
      Serial.print("failed, rc =");
      Serial.print(client.state());
      Serial.print("Try Again in 5 Seconds");
      // WAIT 5 Seconds Before Retrying
      delay(5000);
    }
  }
}

The new skills of the TDMM require two more libraries:  The classic WiFi library of the 8266 processor family, as well as the not quite as known MQTT-Library . For us, this library takes over the publication of the data and the connection to the MQTT broker.

The first 15 lines remain except for the two new ones including for these libraries unchanged. In lines 17… 19, the credentials of your WLAN and the IP address or the name of the MQTT broker follow. If you work with dynamic IP addresses, you will use the name there. If static IP addresses are used for the server, its static IP is here.

In lines 25 ... 27 we form the necessary authorities. After that, the program continues as you already know it.

in the set up() If the WiFi connection is then initiated, as well as our MQTT server on port 1883. On this port, the operation runs unencrypted. Encrypted operation is also possible.

Automate zero position for electricity measurement - another improvement

In set up() Line 80 is the function Current () called. The current measurement was outsourced to this function. Here it is called once to measure the zero-shot stream. The following lines serve to zero the current measurement. The "Mid" factor is gradually adjusted, which now takes over the zero position of the Hall voltage. That works quite well. You should short -circuit the two sockets of electricity measurement for this comparison before starting the TDMM.

The electricity measurement with the Hall element is reasonably sensitive. For the practical application, I can recommend placing the TDMM on the laboratory table, then turn it on and then no longer move - if possible - if magnetic fields are nearby. And that can be every magnetic field of a transformer, magnets ... whatever. A neodymium magnet is enough.
Measurement in the loop ()
After we have set up everything, there is in the Loop () Not much new code anymore. Right at the beginning it is checked whether the connection to the MQTT broker is. If not, the system goes into the reconnect loop and restore the connection. With each grinding run, the call is called client.loop ();.

Now we only need to send the data to the display after each measurement and with client.publish (….) To the right topic of the MQTT broker. More is no longer necessary.

Representation of the measured values ​​on a mobile phone

There are several MQTT apps, many of them free of charge that can read and represent MQTT-Topics. Usually you can send a lot more, e.g. also send data to the broker to control processes, to switch on and off objects, hand over values ​​for a setting, etc.

In our case, an iPhone app is used and namely "IoT MQTT Panel". This app can be found in the Appstore. It is free of charge and works properly. There are a variety of options, information, values, pure binary data and more. There is something similar for Android phones.

I selected for this example:

   Graphic representation of the topic "MQTTUSER/TDMM/voltage" at the top. The app automatically scales. The voltage leap to 5.2 V and back is presented properly - otherwise you would only see a line on the graphic at 5.8 V. The x-axis shows the time of the measurements.

   In the middle the representation of the same topic with the "Gauge" function, which a measuring device with pointer is. Further detail settings are also possible for this.

   At the bottom the topic "MQTTUSER/TDMM/resistance as a pure text field. You see a resistance of 4.7 kΩ between the terminals on the TDMM.  The places behind the comma are irrelevant.

You can see in the photo that the presentation corresponds exactly to the values ​​of the TDMM.

Representation in the home assistant

Many readers will Home Assistant know a widespread software solution for home automation. Personally, I think this project is great, especially because it can be expanded as desired. Even self-developed python scripts can be integrated.

In this case I made the HA a "Lab Assistant". To do this, the HA must first be aware of the MQTT entities, which you can do with the file editor.

Then the HA needs a restart. After that, the entities are available and can be used anywhere. You will remember that Mosquitto runs on the HA and as a so-called "add-on". Load, configure - done. A comfortable solution without a frills.

As soon as these steps are completed, you can set up a new dashboard for the measurement results. I did this with several measurements of the TDMM at the same time, even to emphasize the beautiful property of the TDMM again: all measurements are made at the same time. If you know ha, you no longer need information about what dashboards can look like. My example looks like this:

You see the pure value presentation in the left column. In the middle I have shown tension and electricity with the "Gauge" function. On the far right is the resistance value in a single display, including the performance as a graphic.

HA offers a lot more elements to display. There are plugins with comfortable graphics, partly with average formation, standard deviation and much more. Here you can only see a look at the abundance of possibilities.

Takeover of the data by a Python script

Many of us certainly also work with Python. In professional measurement technology, measurement programs are often written or measurements are automated. You don't necessarily need to use Labview or another, complex framework. Python can be used directly without detours. The library paho.mqtt.client used.

Here is a simple script without a frills that picks up and represents the values ​​of the TDMM:

Download python script

The comments should illustrate sufficiently what the individual functional calls cause.
Of course, they adapt the credentials to their respective network.

As a result, the script delivers to the topic with every new "publish"  MQTTUSER/TDMM/voltage
the value  on the screen.

If you want to save these values, for example, in a postgres database, only a few steps are now required to comfortably store a whole series of measurements. Then you evaluate them, calculate if necessary. Statistical sizes, average, standard deviation etc.

Conclusion

If I managed to convey the benefits of MQTT as a protocol for our purpose and to illustrate the simple handling something, the goal is achieved for today.

Now I wish you a little bit of patience and lots of fun with the TDMM and its possibilities for practical implementation.

outlook 

The upcoming part 6, the last part of this blog article series, leads you to applications of the TDMM with expanded programming and control. You will see how such a compact, inexpensive device also copes with applications that can almost be called "professionally".

Until then
Your Michael Klein

DisplaysEsp-8266Projekte für anfängerSensorenSmart home

Laat een reactie achter

Alle opmerkingen worden voor publicatie gecontroleerd door een moderator

Aanbevolen blogberichten

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery