Non-contact voltage detection sensor for panel

I use a generator interlock, so when the grid power comes back the only thing that changes in my panel is voltage on the wires above the main breaker, as I am powering the rest of the panel through an interlock’d breaker.

I hate the idea, even fused, of trying to attach an indicator light to hot service entry leads (which I’ve seen recommended).

Are there esphome/esp32 compatible sensors that are proximity based, so I could mount it (for example) on the insulated area of those entry wires and sense when they have voltage? I have a suitable external box already for the ESPHOME outside the panel (I use it for iotawatt).

Note since I won’t draw power until I throw the interlock, I can’t use the current transformers I already have on it, as there’s only voltage not current.

Linwood

Something like this?

Well, yes, but maybe I need to read it a couple more times, I didn’t see a working solution, or did I miss it?

Not including the outlet testing and wiring to the service entry (which sounds high dangerous without a fuse).

Is there a working design I missed?

120/240V to logic level optoisolator (with schematic) - YouTube
Well, but this is not non-contact, though.

Could you not just use a non contact ‘wand’ and hikack the output from that to make a pin go hi on an ESP? They are three volt and so you could even power the wand from whatever you’re using to power the
ESP.

There’s a YouTube video linked here that shows how to do this: GitHub - RalphBacon/Safer-Mains-Detection: How to detect the presence of mains electricity (in your home) using a RasPi or Arduino

However, I’ve built this circuit on a breadboard 3 different times and have been unable to get it to work reliably.

If you try it and are successful, please report back.

Could you not just use a non contact ‘wand’ and hikack the output from that to make a pin go hi on an ESP?

That’s an interesting idea, I need to go get a couple cheap ones and experiment.

While looking further for options I stumbled across a product called Powerback (THP108) that serves this purpose though it is an audible alarm not something HA integrated.

I’ve seen a bit of mixed signals on it working, but it’s already made to go in a panel in a knockout, it certainly may be an easier choice.

A contact sensor is easier, but my problem is the mains power to the breaker is not switched (you have to pull the meter to power it off). Anything that has to connect electrically to that wire means working on it hot - solder, screw, wire wrap, whatever. I’m fairly comfortable working around hot wires but that seems just too risky.

I’m note even sure how I feel about wrapping the Powerback wire around the insulation. I need to go open up the panel and see how much working space I have.

But the death-stick idea above (non-contact voltage pens) is interesting for another reason. I don’t really need an alarm to wake me up, I just want something I can check easily. I need to go see if I can get a reading on the service entry cable itself. Maybe I’ll just use that. It’s not as elegant as a HA integrated system, but it’s rarely needed.

I’ll look further at some of the circuits given above. Maybe I’ll build something also.

But thanks everyone for the ideas.

Linwood

Your case should be quite easy since you don’t have interferences from other wiring when power is off. It’s much harder to detect (NCV) some specific wire surrounded by hot wires.

Anyway, I would be surprised if your code doesn’t allow certified indicator led on the supply side. Din rail indicators cost just few bucks. That you can detect with (few bucks) esphome board and phototransistor.

Well, depends on how close “hot” is. I do have a lot of exposed service entry wire (insulated) at the top, would be easy to wrap stuff around. I’m pleasantly surprised there is almost no exposed conductor; this is a new panel and they have all sorts of plastic shields over the SE conductor attachment points.

But when I’m on battery/generator there are a number of hot wires crossing over (literally touching) the service entry cables. So… just depends on how close is close.

I have no idea of the code for direct wired indicator LED’s. I can’t recall ever seeing one on a panel. Frankly a “hot” LED on the panel inputs would seem like a really cheap safety add-on from Eaton (etc), but never seen one on residential stuff.

Ask electrician. For device like this.

So this isn’t really what you asked for OP, but I am planning an interlock switch and am going to have the same problem to solve. I have a smart meter so recently built an ESPHome device with an SX1276 transceiver that listens for the broadcasts from my smart meter. It’s the same signal the PoCo uses to read my meter. I use the presence/absence of that signal to toggle a binary_sensor for grid status. As in if it doesn’t hear a broadcast for 2 mins (adjustable) it toggles the sensor off and when it hears the broadcast again it toggles it back on. Side benefit I also get my consumption data into HA from the broadcast.

Figured I’d mention another non-contact way to approach this if your meter also broadcasts a signal.

1 Like

Now that’s a really cool idea. I stared at my (smart) meter the other day, wondering if I could somehow recognize that the display was changing (and sort it from shadows and such), but that seems much more straightforward, and I assume I can put the receiver indoors.

I assume I can’t tell if it broadcasts regularly and on a suitable frequency ahead of time?

Did you post your working setup anywhere and/or care to share the yaml and I’ll hunt for wiring.

Give me a little bit to cleanup and sanitize what I have and I’ll post my YAML. Current state is a POC and I have some extra stuff in there… I have a buddy that has a similar need but doesn’t use HA or any other automation system. He has an iPhone so I used a Homekit component to expose the grid status as a switch so he’d be able to see status easily in the Home app. (I know exposing it as a switch is weird since you can’t actually control it, but I wanted it to show up right on the main screen of his Home app, and this works fine)

I don’t know how to tell you how to determine if or how your meter broadcasts – you’ll probably just need to look it up. I can tell you mine broadcasts many times per minute. Mine is on 912.6Mhz. I had previously played with a Software Defined Radio (SDR) so already knew my meter was broadcasting and knew my meter ID.

Where would you find that?

Just randomly google’ing I found that they use 902-928mhz, and says it uses “frequency hopping spread spectrum”.

Yours is a fixed frequency?

Google the term “smart meter SDR”.

Mine is using OOK modulation and and I think what you’re describing is FSK? Everything I found when researching this says power meters use OOK for ERT-SCM. What I will say is that the config I’m pasting below will log ANY ERT-SCM messages it sees. I also have it add all of the IDs it sees to a text sensor. I did this to make it easier for someone to try to find their meter. I already knew mine so didn’t need that functionality but figured why not. If you start receiving signals you should be able to figure out which is yours by looking at the ID and KwH number and then looking at your meter to see what matches - that’s how I originally found mine.

Here’s my config:
** Disclaimer - I’m not a developer and my code probably shows that.

esphome:
  name: ##REDACTED##
  on_boot:
    priority: -10 # Runs after everything is initialized
    then:
      - binary_sensor.template.publish:
          id: grid_power_status
          state: OFF
      - script.execute: watchdog_timer 

esp32:
  board: esp32dev
  framework:
    type: esp-idf

# Enable logging
logger:
  level: INFO 

api:

ota:
  platform: esphome

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

web_server:

external_components:
  - source: github://juanboro/esphome-rtl_433-decoder
    components: [ rtl_433 ]

globals:
  - id: last_reading_timestamp
    type: int
    initial_value: '0'

spi:
  clk_pin: GPIO18
  mosi_pin: GPIO23
  miso_pin: GPIO19

sx127x:
  id: sx1276_radio
  cs_pin: GPIO25
  rst_pin: GPIO22
  frequency: 912.6MHz
  modulation: OOK
  bitrate: 32768
  bandwidth: 250_0kHz 
  packet_mode: false
  rx_start: true
  bitsync: false
  rx_floor: -90.0  # Ignores weak noise that might be jamming the decoder

remote_receiver:
  id: rf_receiver
  pin: 
    number: GPIO2
    mode: INPUT_PULLUP
  dump: [] # Turn off raw; we know the signal is perfect now
  buffer_size: 25000
  idle: 25ms 
  filter: 20us
  rmt_symbols: 512 

rtl_433:
  id: my_decoder
  receiver_id: rf_receiver
  on_json_message:
    then:
      - lambda: |-
          std::string output;
          serializeJson(x, output);
          ESP_LOGW("METER_HIT", "JSON: %s", output.c_str());

          if (x.containsKey("id") && x.containsKey("model")) {
            std::string model = x["model"].as<std::string>();
            
            // Only proceed if it's an ERT-SCM (Power Meter) message
            if (model == "ERT-SCM") {
              std::string new_id = x["id"].as<std::string>();
              std::string current_list = id(detected_ids_list).state;

              // Deduplicate and check character limits
              if (current_list.find(new_id) == std::string::npos && current_list.length() + new_id.length() < 250) {
                if (current_list.empty() || current_list == "Unknown" || current_list == "Never heard") {
                  id(detected_ids_list).publish_state(new_id);
                } else {
                  id(detected_ids_list).publish_state(current_list + ", " + new_id);
                }
              }
            }
          }

          // Convert the text input value to a long integer for comparison
          long target_id = atol(id(target_meter_id).state.c_str());

          if (x["id"].is<int>() && x["id"] == target_id) {
             // Use the new ArduinoJson 7 syntax to check for the keys
             if (x["consumption_data"].is<float>()) {
                id(meter_reading).publish_state(x["consumption_data"]);
             } else if (x["consumption"].is<float>()) {
                id(meter_reading).publish_state(x["consumption"]);
             }
             id(last_reading_timestamp) = millis() / 1000;
             id(grid_power_status).publish_state(true);
             id(meter_last_seen_text).update();
             id(watchdog_timer).stop();
             id(watchdog_timer).execute();
          }

sensor:
  - platform: template
    name: "Power Meter Reading"
    id: meter_reading
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

binary_sensor:
  - platform: template
    name: "Grid Power Status"
    id: grid_power_status
    device_class: connectivity

text_sensor:
  - platform: template
    name: "Meter Last Heard"
    id: meter_last_seen_text
    icon: "mdi:clock-outline"
    update_interval: 30s
    lambda: |-
      if (id(last_reading_timestamp) == 0) {
        return {"Never heard"};
      }
      uint32_t now_s = millis() / 1000;
      uint32_t diff = now_s - id(last_reading_timestamp);
      
      if (diff < 60) return {to_string(diff) + "s ago"};
      if (diff < 3600) return {to_string(diff / 60) + "m ago"};
      return {to_string(diff / 3600) + "h ago"};

  - platform: template
    name: "Detected Meter IDs List"
    id: detected_ids_list
    icon: "mdi:format-list-numbered"

text:
  - platform: template
    name: "Target Meter ID"
    id: target_meter_id
    optimistic: true
    min_length: 1
    max_length: 12
    initial_value: "##REDACTED##" 
    restore_value: true       
    mode: text
    entity_category: config
    on_value:
      then:
        - script.execute: watchdog_timer 

number:
  - platform: template
    name: "Watchdog Delay Minutes"
    id: watchdog_delay_mins
    optimistic: true
    min_value: 1
    max_value: 30
    step: 1
    initial_value: 5
    restore_value: true
    unit_of_measurement: "min"
    mode: slider
    entity_category: config
    on_value:
      then:
        - script.execute: watchdog_timer 

script:
  - id: watchdog_timer
    mode: restart # Restarting resets the delay timer
    then:
      - delay: !lambda |-
          // Convert minutes from the number component to milliseconds
          return id(watchdog_delay_mins).state * 60 * 1000;
      - lambda: |-
          ESP_LOGW("WATCHDOG", "No signal for %.0f minutes! Grid down.", id(watchdog_delay_mins).state);
          id(grid_power_status).publish_state(false);


button:
  - platform: restart
    name: "Restart"
    entity_category: config

  - platform: factory_reset
    name: "Factory Reset"
    id: Reset
    entity_category: config

  - platform: safe_mode
    name: "Safe Mode"
    internal: false
    entity_category: config

Ah… thanks. I found the meter’s FCC cert but it didn’t tell me much. But I see some things there.

I think I’ll order one and play.

Thank you @k8gg and @bradmck for the code.

No problem. An SDR is a fun little device to play with anyways. You can find neighbor’s weather stations, motion sensors, temp sensors, curtain controllers, etc. You can also do stuff like receive radar maps from weather satellites and other nerdy things.

I just happened to have built the device I shared my code for about a week ago so it’s all very fresh. It’s also a little bit of a work in progress but is working well for me so far. And I forgot to answer one of your questions: Yes, my device is inside my house. It had to me much closer to my meter than I anticipated but right now I’m just using a simple piece of wire for the antenna (but the correct length).