Archive for the Wireless manual PnP Pump Category

EMI oy, oy, oy vey

Posted in ESP32, Manual PnP, PnP, Wireless manual PnP Pump on December 19, 2022 by asteriondaedalus

The idea was, actually, to run the ESP32 pair (pedal and pump) off battery – for the portable aspect.

The 12VDC power to the vacuum pump and to the pneumatic solenoid would be separated BECAUSE that would go through the NO circuits of two relays on the relay shield.

Couldn’t be simpler.

Even if powering the pump by USB or power jack, there is no denying that there is plenty of air gap between the power supplies of the ESP 32 based WEMOS D2 R32 and the pump and solenoid.

And yet, the pump device crashes the moment the first relay, the one for the pump, comes on. You can tell, in the video, the LED for the associated relay blinks on then off, ever so quickly.

FRACK, it just shouldn’t be so.

Except, it may be EMI? It can’t be power spikes, due to the back EMF of the motor, since the power circuits are separate.

I will have to get out me CRO.

CAW CAW

Turns out, the problem is the DIY CAW, so sorry, DIY MORE battery shield FRAGGING whenever the first relay is being turned on. No, really it is, I just took the battery shield out of the loop, and powered the pump device by USB and the issue disappeared.

DOH!, I worked out the issue. Was simply a short between the battery shield and the relay shield.

Code for pump and pedal is now posted.

ESP32-(K)NOW how?

Posted in ESP32, Manual PnP, PnP, Wireless manual PnP Pump on December 12, 2022 by asteriondaedalus

Gotta luv the internet. So, some people are telling you to use STA for the controller, and a WiFi.disconnect() afterwards. Others both the master and slave use STA but neither need a WiFi.disable().

The venerable Circuit Cellar is telling you set up the “slave” as an AP as well as use WiFi.disable() with the STA for the “master”. Essentially, the opposite of what I muddled into myself. Not convinced.

So, it just seems to “depend” upon whom you get to first on the internet, and given it’s hard to get an authoritative source since so many are just also regurgitating crap from other web pages.

DOH! And double FRACK!

Now I have found that the “pedal” (aka “controller” aka “master”) as WIFI_AP_STA with WiFi.disconnect(), and “slave” aka “peer” as STA, mitt no disonnect(), can either behave for quite a time (probably dependant upon Elon the King Twit’s twit count on the day), before then failing utterly to send a message successfully.

Noting the variations in how people are trying the ESP-NOW setup, all I can do is try them all, to see if at least one provides a higher QOS.

I got rid of the AP and simply with STA on both devices. I assumed, since ESP-NOW was talking protocols, it may be simply using the WiFi as a “carrier”. Since STA both transmit and receive, I am assuming that we are using something low level? I did eventually find an OSI stack picture equivalent, vs ESP-NOW, in my Net trawling.

Also wik, if you do understand WiFi.disable(), it does disconnect from the network BUT leaves the wifi widgetry up! Didn’t seem to matter, however, at least on the small number of pedal presses I did to test each option.

The table below shows some experiments with different WiFi setups.

“Master”“Slave”Works
WiFi.mode(WIFI_STA);WiFi.mode(WIFI_STA);YES
WiFi.mode(WIFI_STA);
WiFi.disconnet();
WiFi.mode(WIFI_STA);YES
WiFi.mode(WIFI_STA);
WiFi.disconnet();
WiFi.mode(WIFI_STA);
WiFi.disconnet();
YES (pick this one)
WiFi.mode(WIFI_STA);WiFi.mode(WIFI_STA);
WiFi.disconnet();
YES
WiFi.mode(WIFI_AP);WiFi.mode(WIFI_STA); NOPE!
WiFi.mode(WIFI_AP_STA);
WiFi.disconnet();
WiFi.mode(WIFI_STA); YES (BUT)
Experiments

So, I had been using AP and having fun with that, so assumed that was what was needed. My fault, I do jump the gun.

The intermittent behaviour, that I was seeing when using WIFI_AP_STA may simply be the AP stealing processing from the STA? When using the straight STA there is no lag (really) on connection between the two units. Once the “Pump connected!” message comes up, it stays up (except for, as it turns out, annoying times it extinguishes again). You can turn the “pump” off then on and everything is happy, without any fancy reconnect code. All of this, since it is simply a protocol over the WiFi channel, with the mac addresses being used to target devices.

However, I was disappointed to find that even with using straight STA, and with WiFi.disconnect(), the messages would eventually stop going through. Reboot of the “pedal” seemed to fix that. Seems rare and intermittent, so I may still need to understand the problem, to see if there is a means for the devices to sort themselves out.

Turns out you can set up with AP, but it needs a WiFi.disconnect(). Though not buried in the ESP-NOW site. The story is even funkier, because:

  WiFi.persistent(false);
  WiFi.mode(WIFI_AP);
  WiFi.disconnect();
  WiFi.softAP("ESPNOW", nullptr, 3);
  WiFi.softAPdisconnect(false);

You guessed it, the ..., 3); is channel 3.

And that’s on both the “initiator” and the “responder”.

But wait. Let me look, …

Yep, nope. Using that code on both “initiator” and “responder” sees no connection between the two. That may be because I have only registered the pump as a peer to the pedal, and not vice versa.

Gimme a moment, …

tap, tap, tappity tap, tap , ... , DOH!
Nope, not a sausage, or should I say banana?

However, that may work with the (so-called) “yoursunny” WiFiEspNOW library. I won’t even dignify the Circuit Cellar offering with an experiment.

Since it is more intuitive if you understand what chunks of the OSI model ESP-NOW replaces, rather than discussion around not needing the Wi-Fi, I’ll stick with the following on both devices:

WiFi.mode(WIFI_STA); 
WiFi.disconnet();

ESP-NOW … and then

Posted in ESP32, Manual PnP, PnP, Wireless manual PnP Pump on December 11, 2022 by asteriondaedalus

I have tried, unsuccessfully, to get a MQTT broker running on the ESP32, despite some offerings (too many still in work). I did then find articles on ESP-NOW, which is a peer2pear setup over WiFi. Hence, I opted to rewrite my PnP pneumatic setup as ESP-NOW.

The setup will comprise an Wemos BT with battery (wemosbat under PlatformIO devices) as a WiFi foot pedal and AP, with a quad relay shield sitting on a Wemos D1 R32. The D1 R32 will control a pneumatic solenoid and a pump. You want to get the pump spun up BEFORE you upon up the pneumatic solenoid, and close the solenoid BEFORE you shut down the pump.

Currently, the “pump” needs to be turned on before the “pedal”. I still need to investigate how ESP-NOW handles loss of connections/reconnections.

PEDAL

The pedal has a SSD1306 132×32 pixel display to let you know when the two devices are connected, and also the state of the pedal press.

void setup() { // of ESP-NOW "master" and an ESP32 AP to boot
  Serial.begin(115200);
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    return;
  }
  
  // setup access point
  WiFi.mode(WIFI_AP_STA);
  WiFi.disconnect();
  
  delay(1500);
  WiFi.softAPConfig(local_ip, gateway, subnet);
  WiFi.softAP(ssid, password /* , channel, hide_SSID, max_connection*/);
  delay(1500);
  Serial.print("\nMAC: ");
  Serial.println(WiFi.macAddress());
  // start ESP-NOW
  InitESPNow();
  registerCallback();
  // setup pedal input
  bounce.attach( BOUNCE_PIN ,  INPUT );
  bounce.interval(5); // interval in ms
  displayUpdate(bounce.read(),pumpPresence);
  // LED SETUP
  int ledState = HIGH;
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, ledState);
  // add peer
  registerPeer();
}

The trick to get the two to talk together, as AP/STA pair, was the following code on the AP device.

 WiFi.mode(WIFI_AP_STA);
 WiFi.disconnect();

I had found the trick with the WiFi.disconnect() associated with an STA based “master”. The code does not talk to the “peer” unless the “master” has STA (apparently). Blowed if I know why you need the WiFi.disconnect()?! As usual, it turns up in a hack someone has done, but the “why” is not included. I had started with:

 WiFi.mode(WIFI_AP);

Throughout, pumpAddress is your usual (example only):

uint8_t pumpAddress[] = {0x84, 0xCC, 0xA8, 0x2C, 0x0D, 0xA8};

PUMP

So, the pump doesn’t need any real tricks. Just connect to the AP and then init ESP-NOW and add your OnReceive callback.

void setup() { // of "slave" peer, will be on wifi setup by ESP32 AP
  Serial.begin(115200);
  
  // setup access point
  WiFi.mode(WIFI_STA);
  if (!WiFi.config(local_IP, gateway, subnet)) {
    Serial.println("STA Failed to configure");
  } else {
    Serial.print("STA configure as local IP: ");
    Serial.print(local_IP);
    Serial.print(" gateway: ");
    Serial.print(gateway);
    Serial.print(" subnset: ");
    Serial.println(subnet);
  }
  
  WiFi.begin(ssid, password);
  while(WiFi.status() != WL_CONNECTED){
    Serial.print(".");
    delay(100);
  }   
  Serial.print("\nMAC: ");
  Serial.println(WiFi.macAddress());
  // start ESP-NOW
  InitESPNow();
  esp_now_register_recv_cb(OnDataRecv);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LED_OFF);
}

HELPERS

For this application, the registerPeer() function only needs to add a single “peer” in this app. But there is a raft of other “peer” related functions that may need investigation, since the simplest setups appear not to allow for a re-connect of peer (if it goes down then comes up again).

void registerPeer (void) { 
  memcpy(peerInfo.peer_addr, pumpAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  esp_err_t status = esp_now_add_peer(&peerInfo);
  switch (status)
    {
    case ESP_OK:
      Serial.println("Peer registered");
      break;
    case ESP_ERR_ESPNOW_NOT_INIT:
      Serial.println("ESP NOW not actually initiated");
      break;
    case ESP_ERR_ESPNOW_ARG:
      Serial.println("ESP NOW error in argument");
      break;
    case ESP_ERR_ESPNOW_FULL:
      Serial.println("ESP NOW peer list is full");
      break;
    case ESP_ERR_ESPNOW_NO_MEM:
      Serial.println("ESP NOW no memory");
      break;
    case ESP_ERR_ESPNOW_EXIST:
      Serial.println("ESP NOW peer has existed");
      break;   
    default:
      Serial.println("Unknown error peer registration");
      break;
    }
}

For the AP, I opted for full debug on status return of the pedal message send in pedalPressed(). This actually help understand why, in my first attempts, the “master” and “slave” were not talking. This was despite the “slave” appearing to find and connect to the AP.

I thought, originally, that the “master” and “slave” were not talking because I was never getting a callback function trigger. At first, I thought that was an error in callback registration. The debugging messages of the call back register function (see next function) were, however, always happy.

It turned out the problem was I needed the change from AP to AP_STA. The error I started getting back, when I used pedalPressed(), was “ESP NOW peer wifi mismatch” (aka ESP_ERR_ESPNOW_IF).

void pedalPressed (void) {
  pumpMessage.pumpFlag_msg = PEDAL_PRESSED;
  esp_err_t status = esp_now_send(pumpAddress, (uint8_t *) &pumpMessage, sizeof(pumpMessage));
  pumpPresence = PUMP_UNAVAILABLE;
  switch (status)
  {
  case ESP_OK:
    Serial.println("Pedal press sent");
    pumpPresence = PUMP_PRESENT;
    break;
  case ESP_ERR_ESPNOW_NOT_INIT:
    Serial.println("ESP NOW not actually initiated");
    break;
  case ESP_ERR_ESPNOW_ARG:
    Serial.println("ESP NOW error in argument");
    break;
  case ESP_ERR_ESPNOW_INTERNAL:
    Serial.println("ESP NOW internal error");
    break;
  case ESP_ERR_ESPNOW_NO_MEM:
    Serial.println("ESP NOW no memory");
    break;
  case ESP_ERR_ESPNOW_NOT_FOUND:
    Serial.println("ESP NOW peer not found");
    break;   
  case ESP_ERR_ESPNOW_IF:
    Serial.println("ESP NOW peer wifi mismatch");
    break; 
  default:
    Serial.println("Unknown error in send");
    break;
  }
}

The function registerCallback is mostly to keep the code clean.

void registerCallback (void) {
  esp_err_t cbstatus = esp_now_register_send_cb(OnDataSent);
  switch (cbstatus)
  {
  case ESP_OK:
    Serial.println("cb registered");
    break;
  case ESP_ERR_ESPNOW_NOT_INIT:
    Serial.println("ESP NOW not actually initiated");
    break;
  case ESP_ERR_ESPNOW_INTERNAL:
    Serial.println("ESP NOW internal error");
    break;
  default:
    Serial.println("Unknown error in cb registration");
    break;
  }
}

So to the function InitESPNow().

void InitESPNow(void) {
  //If the initialization was successful
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  //If there was an error
  else {
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
}

Therefore, there may be more to setting up ESP-NOW, that requires a little work to find the real destructions.