emonTx4 & Pi pico

I’ve been doing a little EmonTx v4 & Pi Pico testing to explore what’s possible following @borpin’s recommendation. I’ve been able to get a basic serial to emoncms bridge working so far that meets the core requirement of sending the EmonTx data to emoncms but with a hardcoded SSID and WiFi password of course.

I’ve got an example working with both micropython and the arduino pi pico core. Code examples included below for anyone interested in this.

I think a small adapter pcb could work well for making this a connectivity option on the emonTx v4.

MicroPython


import network
import socket
from time import sleep
import machine
from machine import UART, Pin

import urequests
import uselect
import sys

ssid = 'SSID'
password = 'PASSKEY'

def connect():
    #Connect to WLAN
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)
    while wlan.isconnected() == False:
        print('Waiting for connection...')
        sleep(1)
    ip = wlan.ifconfig()[0]
    print(f'Connected on {ip}')
    
try:
    connect()
except Exception as e:
    machine.reset()

buffered_input = []

uart0 = UART(0) # defaults 115200 baud

while(True):
    
    while uart0.any() > 0:
        c = chr(uart0.read(1)[0])
        buffered_input.append(c)

    if '\n' in buffered_input:
        line_ending_index = buffered_input.index('\n')
        data = "".join(buffered_input[:line_ending_index]).strip()
        buffered_input = []
        
        if data[0:3]=="MSG":
            req = "https://emoncms.org/input/post?apikey=apikey&node=emontx4pico&data="+data
            print(req)
            r = urequests.get(req)
            print(r.content)
            
    sleep(0.1)

Arduino Pi Pico core

#include <WiFi.h>
#include <HTTPClient.h>

// Replace with your network credentials
const char* ssid = "SSID";
const char* password = "PASSKEY";

String serverName = "https://emoncms.org/input/post";

String line = "";
String data = "";
String sub = "";
int data_ready = 0;

void setup() {

  // Start the Serial Monitor
  Serial.begin(115200);

  Serial1.begin(115200);

  // Operate in WiFi Station mode
  WiFi.mode(WIFI_STA);

  // Start WiFi with supplied parameters
  WiFi.begin(ssid, password);

  // Print periods on monitor while establishing connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    delay(500);
  }

  // Connection established
  Serial.println("");
  Serial.print("Pico W is connected to WiFi network ");
  Serial.println(WiFi.SSID());

  // Print IP Address
  Serial.print("Assigned IP Address: ");
  Serial.println(WiFi.localIP());

}

void loop() {

  while (Serial1.available()) {
  
    char c = char(Serial1.read());
  
    if (c=='\n') {
        data = line;
        data.trim();
        line = "";
        
        sub = data.substring(0, 3);
        if (sub=="MSG") {
            Serial.println(data);
            data_ready = 1;
        }
    } else {
        line = line + c; 
    }
  }

  //Send an HTTP POST request every 10 minutes
  if (data_ready) {
    data_ready = 0;
    //Check WiFi connection status
    if(WiFi.status()== WL_CONNECTED){
      HTTPClient http;

      String serverPath = serverName + "?node=pico2&data="+data+"&apikey=APIKEY";
      Serial.println(serverPath);
      
      // Your Domain name with URL path or IP address with path
      http.begin(serverPath.c_str());
      
      // Send HTTP GET request
      int httpResponseCode = http.GET();
      
      if (httpResponseCode>0) {
        Serial.print("HTTP Response code: ");
        Serial.println(httpResponseCode);
        String payload = http.getString();
        Serial.println(payload);
      }
      else {
        Serial.print("Error code: ");
        Serial.println(httpResponseCode);
      }
      // Free resources
      http.end();
    }
    else {
      Serial.println("WiFi Disconnected");
    }
  }
}
1 Like

The adapter PCB arrived, I havent spent a lot of time on adding silk screen text etc on this version yet but it’s working as a quick functional test.

On the right hand side there is the option to connect the RFM69cw radio to the Pico SPI and the DS18B20 temperature sensor input to a Pico digital input. These could allow the Pico to take over control of these components potentially allowing the EmonTx to be used as a RFM radio base-station as well as allowing for the reading of the DS18B20 addresses - I havent tested or written any code for those functions yet. I have only tested the serial interface so far.

2 Likes

Apparently, there is now a PiPicoW (with Wi-Fi)

Thanks @borpin, yes the wifi version is the variant Im using above, seems to work well!

1 Like

I can see this ending up as the default configuration IMHO.

Just a thought - will the six CT extender board fit under the pico adapter? If not, perhaps the pico could be rotated through 90 degrees as in the Pi zero adapter …

Good point, I am a bit constrained in it’s orientation by my choice of header location for the uart and spi, so it may be an either/or for the first batch at least. What I thought was a good approach for mechanical rigidity isn’t the best for mounting the pi pico or pi zero. I am actually planning on changing the header locations and layout on the next version to fix this.

1 Like

Thanks for the update. To be fair, a crystal ball would be useful, as I think the Pico W was only launched at the end of June this year!

1 Like

thumbsup beer_cheer

2 Likes

FYI, it looks like support by ESPHome for the PiPicoW is extremely close :grinning: :clap:

1 Like

ESPHome support for the RP2040 chip will be released from Dev on Wednesday (16/11/22). Looking forward to see if my ESPHome component ‘just works’ :slight_smile:

As I’d want wired ethernet it would be nice if the W5500-EVB-Pico variant could be supported.

Yes. I was unaware that there were any other boards using that chip. In general, if the chip is supported in PlatformIO then ESPHome can support it. Support for even the RPi board (with ESPHome) is limited at present and will need someone to pick it up. As ever, it works enough for the Dev who did the work and he has no incentive to expand that - the nature of these projects. For instance, MQTT is currently unavailable and the Dev doesn’t use MQTT so it is low priority!

However, the flip side is that if OEM have the software components that work with ESPHome, an unlimited number of boards are then available to the end user.

Just to clarify, my comment re support for the ethernet equipped Pico was primarily regarding Trystan’s work on an adapter board, as I’d be wanting to feed emoncms in a similar manner to the sample code he posted earlier for the wireless variant.

I’ve got mine working now :slight_smile:

I slightly improved the MicroPython to handle instances where Emoncms is down (it would not recover on its own). I also made the LED blink on transmission. Timeout very quick as it’s on the LAN. I did consider async queues and stuff but I’m not skilled enough for that!

import network
import socket
from time import sleep
import machine
from machine import UART, Pin
import urequests

ssid = 'SSID'
password = 'PASSWORD'

def connect():
    # Connect to WLAN
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)
    while not wlan.isconnected():
        print('Waiting for connection...')
        sleep(1)
    ip = wlan.ifconfig()[0]
    print(f'Connected on {ip}')

try:
    connect()
except Exception as e:
    machine.reset()
    
print('Starting EmonCMS client')

buffered_input = []

uart0 = UART(0)  # defaults 115200 baud

led = Pin("LED", Pin.OUT)

while True:
    while uart0.any() > 0:
        c = chr(uart0.read(1)[0])
        buffered_input.append(c)

    if '\n' in buffered_input:
        print('Got event')
        line_ending_index = buffered_input.index('\n')
        data = "".join(buffered_input[:line_ending_index]).strip()
        print(data)
        buffered_input = []
        
        if data[0:3] == "MSG":
            led.on()
            req = "http://IPADDRESS:8080/input/post?apikey=APIKEY&node=emontx4&data=" + data
            print(req)
            try:
                r = urequests.get(req, timeout=0.5)
                print(r.content)
            except OSError as e:
                print('Connection failure')
            led.off()