Trying to make a puck js doorbell and need advice on range

Posted on
Page
of 2
/ 2
Next
  • Hey folks, long time espruino fan here but I'm running into trouble with my latest idea.

    I've finally gotten into home assistant this year and wanted to set up a smart doorbell - the puck js seemed perfect for this with it's long battery life and plain white casing. I've configured everything so the puck sends advertising data about button state which then gets sent over mqtt via my raspberry pi's bluetooth to HA and it works but only if the puck is in the same room as the pi which is is plugged into my router's ethernet ports. I've bought one of these from the espruino store to help boost the pi's range and it's boosted the range but not enough. I've also upped the transmission power on the puck js with

    NRF.setTxPower(4)
    

    But it's not really changed the total range by any noticeable amount.

    I'm only using this at a distance of ~7 meters but there are a couple of windows and a composite door between the puck and the pi that I can't really get out of the way. Does anybody have any advice on what I could do next to fix this other than setting up a BT to WiFi/MQTT bridge closer to the door? Would adding a usb cable extender to the aerial and putting it higher up than the pi help?

    Thanks!

  • Hi! Actually I've literally just (yesterday) set up something similar with Home Assistant.

    You're doing the right thing running the Pi from Ethernet, but yes, the range can be pretty low through brickwork - Bluetooth LE isn't great for that.

    One thing you could try for starters is right after the button is pressed, increase the advertising interval to maybe 20ms for a minute (default is 375ms) - and that'll throw out a lot more packets that increases your chances of one arriving.

    How are you doing the advertising->MQTT part at the moment?

    When I did it, I used https://bthome.io/ which is built into Home Assistant (and then the https://www.espruino.com/BTHome library). As long as bluetooth is working with Home Assistant you can just advertise in the special format and it appears in Home Assistant without any extra config needed.

    The real benefit is you can use ESPHome (https://esphome.io/components/bluetooth_­proxy.html) on an ESP32 device as a simple bridge - so I've got one of those in the TV cabinet which is close enough to outside that it works (while my Pi with Home Assistant is in the loft).

    Having said that, right now I'm only advertising every 375ms and it's taking several seconds for the button press to get through - so I need to increase the advertising interval (as I'd mentioned above) to help with it.

    Hopefully I'll do a proper writeup on it soon

  • Thank you, good shout on the advertising interval - I assume that will add more drain to the battery though?

    I'm using your espruinohub project with HA integration for the bluetooth->mqtt component but that bthome code looks much, much simpler. I'll try lowering the interval with something like

    function updateAdvertising() {
      NRF.setAdvertising(require("BTHome").get­Advertisement([
        {
          type : "battery",
          v : E.getBattery()
        },
        {
          type : "temperature",
          v : E.getTemperature()
        }
      ]), { name : "Sensor1" });
    }
    
    // Update advertising now
    updateAdvertising();
    // Update advertising every 20 miliseconds...
    setInterval(updateAdvertising, 20);
    

    First and see if that helps, then look into a bridge like you recommend. I was really hoping to avoid a third device in the middle but I guess BT isn't really designed for this even though the range isn't far.

  • Also what are you using as an esphome bridge? A smartplug or similar? I've be interested to see how you are powering it, what exact chip it uses and the range you're seeing if it can contact your router and outdoor puck from inside a tv cabinet. I was going to try tasmota myself as all my other esp devices use that but esphome seems simpler for this specific use case.

  • too bad the nrf52832 chip does not support BLE long range or some lower bitrates with better sensitivity or that it cannot increase tx power more, all that can be done by 52833 or 52840 chips (so in theory could work e.g with Microbit 2), sometime ago I was searching aliexpress for simple cheap nrf52833/40 based tags/beacons with button but did not find any.

    there is older nrf proprietary format than could work between two nrf52 devices which can do 250kbit bitrate but looks like it (unlike BLE long range) does not come with better sensitivity
    https://devzone.nordicsemi.com/f/nordic-­q-a/78469/250-kbit-s-nordic-proprietary-­radio-mode-on-nrf52840
    https://infocenter.nordicsemi.com/topic/­ps_nrf52840/radio.html?cp=5_0_0_5_19_14_­4#unique_103003482

  • so the good news is BTHome works like a treat and means I can treat the doorbell as a proper device with sensors and events etc. The bad news is this doesn't solve the range problem. I think a wifi bridge is my only option here, argh!

  • Also what are you using as an esphome bridge? A smartplug or similar?

    It's a mix - I have a SONOFF thing wired in upstairs which does the hall light, and that runs it - but it wouldn't reach.

    So then I just used an ESP32 board I had kicking around (something like https://www.amazon.co.uk/ESP-32S-Develop­ment-2-4GHz-Bluetooth-Antenna/dp/B071JR9­WS9/ref=sr_1_3) and stuck it in the TV cabinet, powered off the USB supply I use for my Google TV.

    I think Tasmota will do the bridge too? https://tasmota.github.io/docs/Bluetooth­_MI32/ But I'm not sure as I've never used it.

    For advertising, I actually mean:

    function updateAdvertising() {
      NRF.setAdvertising(require("BTHome").get­Advertisement([
        {
          type : "battery",
          v : E.getBattery()
        },
        {
          type : "temperature",
          v : E.getTemperature()
        }
      ]), { name : "Sensor1", interval:20 }); // <---- here
    }
    

    And keep your setInterval the same. It will use more power, but you can for instance do this, based on the code lower down https://www.espruino.com/BTHome:

    var buttonState = false;
    var slowTimeout;
    
    function updateAdvertising() {
      NRF.setAdvertising(require("BTHome").get­Advertisement([
        {
          type : "battery",
          v : E.getBattery()
        },
        {
          type : "temperature",
          v : E.getTemperature()
        },
        {
          type: "button_event",
          v: buttonState ? "press" : "none"
        },
      ]), { name : "Sensor1", interval: buttonState?20:2000 });
      if (slowTimeout) clearTimeout(slowTimeout);
      slowTimeout = setTimeout(function() { 
        slowTimeout = undefined;
        updateAdvertising();
      }, 60000);
      // ensure that subsequent updates show button is not pressed
      buttonState = false;
    }
    // When a button is pressed, update advertising with the event
    setWatch(function() {
      buttonState = true;
      updateAdvertising();
    }, BTN, {edge:"rising", repeat:true})
    
    updateAdvertising();
    NRF.setTxPower(4);
    

    So now, when you press the button it should start advertising quick, but only for 60 seconds while it's advertising a button press, and then it'll go back to being slow (and will still update every 60 seconds).

  • Ooo clever, so even though the once per minute timeout call is recursive it checks for an existing timeout and clears it, then updates the advertising interval when it updates the sensor values based on if the button is pressed or not. I assume we have to clear the existing timeout or it only runs the once?

    The code I have at the moment is very similar btw but I'm not being that clever with the ternary statement I was just setting it to a hard 20ms in the setAdvertising(options) object and using a once a minute timer.

  • I assume we have to clear the existing timeout or it only runs the once?

    It should be fine because we do:

    if (slowTimeout) clearTimeout(slowTimeout);
      slowTimeout = setTimeout(function() { 
      ...
    

    The code I have at the moment is very similar

    Yes, that's good for testing - but you're still not seeing good enough range from it? :(

  • Sadly not - I get more range but only in line if sight to the aerial - anything opaque in the way (wood, walls, whatever) appears to block it.

  • anything opaque in the way (wood, walls, whatever) appears to block it.

    Wow, that's not good at all - especially with the long range aerial. I seem to be able to get through walls/floors here (but 2 walls is pushing it).

    I'd definitely say take a look at ESPHome then... This is what I use in my config.yaml file to enable BTHome:

    esp32_ble_tracker:
      scan_parameters:
        interval: 320ms
        window: 120ms
    
    bluetooth_proxy:
      active: true
    

    By default the scan window is only 30ms every 320ms, so under 10% - so unless you change window away from the default, you're pretty much guaranteed not to receive any of the normal 375ms advertisements in any sensible timeframe.

  • So, the plot thickens. I tried your code pretty much as is and it got through the first wall but not the door. I then noticed I had a usb ssd plugged into the pi right next to the aerial - removing the cable connecting it and voila, it works! Amazing, no need for another extra thing to plug in. The bad side of this is the pi is running my fileshare so I need a way around this - would a usb extender cable to get the aerial away from the pi be a good idea, something like this? Thanks!

  • Oh, the well known USB 3.0 interference issue strikes again!
    https://www.usb.org/sites/default/files/­327216.pdf
    Yes extension or shielding the ssd or both.

  • slaps forehead of course! will this have the same problem over usb 2?

  • Should work in usb 2.0, it is caused by the 5gbit speed. It happened to me too, I was using usb 3.0 ssd with Raspberry Pi 3 for long time and then when I tried this same ssd with Pi4 the wifi in it stopped working. Took me some time to figure out what happened because this thing worked fine in Pi3 (which can do only usb 2.0).

  • If I plug both the aerial and the ssd into the USB 2.0 ports it's still not quite there but I put the ssd into the 2.0 port and the aerial as far away as possible in the USB 3.0 port it works - afaik the problem is the USB 3.0 transfer speed over the cables not the actual ports or controllers themselves. Either way I am very relieved I'm (hopfully) not going to need a bridge for a few meters across the front of the house. Phew!

    PS: I wonder if this means I can now put more beacons/pucks around the house for temperature measurements...

    PPS: Should I be using E.getBattery or Puck.getBatteryPercentage for the battery levels? I can't find a document that explains the differences via the forum or shop page. Thanks!

  • Great! Glad you got it sorted! Being able to use USB3 for your SSD would be nice - what about putting the BLE dongle on an extension lead and getting it as far away from other electrical stuff as possible? They're not very picky so any old extension is fine.

    Then, because your Pi is just using Ethernet anyway, you could put the whole Pi+SSD in a metal box to shield it, and that should really help?

    Should I be using E.getBattery or Puck.getBatteryPercentage for the battery levels?

    It makes no difference, they are the same (but I'd use E.getBattery). Puck.getBatteryPercentage was done first, but then I realised it was handy to have a E.getBattery on every device with a battery, so you didn't have to have Bangle.getBattery, Pixl.getBattery/etc.

    I thought I'd marked Puck.getBatteryPercentage as deprecated, but maybe not - I'll mention it in the docs.

  • Ah, I must be looking at the wrong docs then - it does make sense to have a unified api for shared attributes; I concur. Please let me know the correct link and I shall bookmark that to avoid bothering you needlessly again.

    I was thinking of putting it on a dongle but the issue is figuring out how much length I'd need and how to stop the antenna of the Feasycom flopping about which I imagine could do more harm than good for the signal quality. As the network interface is only 1Gb/s I think ~1/2 that speed isn't a game changer, just an annoyance for now. The drive is mounted as exFat for interoperability/easier data recovery so the speeds were never close to full gigabit anyway. Long term I'll move to a pi 5 with an SSD attached directly over PCIe which should mitigate the problem entirely without needing to mount cables on the wall or add more shielding (I hope!)

    I should add that with the aerial working normally without USB 3 interference I'm seeing much better range than I expected. I tried out using BTHome on my Bangle JS and it was picked up in the 2nd floor bedroom through two different floors! Seems to pick up ThermoPro thermometer units just fine at that range as well.

  • The best reference is https://www.espruino.com/Reference - and there's a specific one for Puck.js which shows you only the stuff that's available: https://www.espruino.com/ReferencePUCKJS­

    I tried out using BTHome on my Bangle JS and it was picked up in the 2nd floor bedroom through two different floors

    That's great! Also those thermometers look neat - I might have to give those a try!

  • Ah, I knew about https://www.espruino.com/Reference but not

    https://www.espruino.com/ReferenceDEVICE­NAME
    

    Which link takes you to the api docs for each device? The links on the main page seem to take you to

    https://www.espruino.com/DEVICENAME
    

    I've bought quite a few of the thermometers and no issues so far - they take an AAA battery and last for months. The only problem is they don't seem to report battery life but for the low price I'll make do. 🙂

  • For anyone else looking at this I just uploaded some videos - it's been a while since I did a fresh Home Assistant install so I'm impressed how it 'just works' out the box.

    https://youtu.be/eQpwemNit4c

    https://youtu.be/mAe6rOHZRgQ

    Which link takes you to the api docs for each device?

    You click on the 📚 next to each device on https://www.espruino.com/Reference - it's a bit too hidden to be honest, but the device-specific reference was something I only added a few months back

  • Ah, perfect! Thanks, I'll bookmark those. Maybe make them text over icons for easier discovery? I wasn't aware those were active links on first glance.

    Home assistant is coming along leaps and bounds - the next release will allow you to export historical CSV data directly from your dashboard widgets amongst other things. I'm impressed with how easily BTHome/ThermoPro devices integrate.

    Re your vid, does it make any sense to hook in the light sensor for the doorbell or is that too inaccurate for calibrated use in daylight? Thanks!

  • PS: Re the other video I assume I can't configure the bangle js "button" BTHome app to work while I'm connected via BT to my iphone as advertisements don't broadcast while a device is paired? Otherwise that looks amazing, I didn't know there was an app for that on the bangle store.

  • does it make any sense to hook in the light sensor for the doorbell

    It's not that accurate really - it's good for telling between light and dark but I wouldn't use it for much else!

    I assume I can't configure the bangle js "button" BTHome app to work while I'm connected via BT to my iphone as advertisements don't broadcast while a device is paired?

    Actually it should 'just work' - new firmwares are able to advertise while connected if you use the right flag in NRF.setAdvertising :)

  • That is very cool as I just updated the firmware for my bangle the other day. I'll take a binary "light" or "dark" as well. Thanks for the content!

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Trying to make a puck js doorbell and need advice on range

Posted by Avatar for Edd @Edd

Actions