Control the pool with HA (Bluetooth pump & 315MHz & pH+REDOX)

Hello everyone,

I use Home Assistant and ESP Home to automate several things at home, and it works well.

So, I’ve automated the management of my swimming pool (temperature readings, filter pressure, lighting, pH and ORP control, as well as the circulation pump).

Temperature, filter pressure, and heat pump control are all working.

I have a problem with the circulation pump, a DAVEY SilensorPro variable-speed pump that only has Bluetooth (no dry contacts) for remote control via a mobile app…

I’d like to replace this mobile app with integration into Home Assistant using the Bluetooth controller of an ESP32 running ESP Home.

I’ve done a lot of research; a Bluetooth proxy seems like the answer, but I don’t know how to set it up… Do you have any ideas?

I was thinking of intercepting the communication between my smartphone and the pump and then replaying it with the ESP32, but how do I do that?

Regarding pH and ORP regulation, I have two pumps with associated probes from the brand PHREDO, which don’t have any interface for remote control.

I would simply like to retrieve the pH and ORP values ​​displayed on 7-segment displays. I’m thinking of connecting an ESP32 in parallel with the display and receiving the signal sent by the controller to the display, then converting it. Has anyone else had this idea?

One last point about controlling the RGB LED spotlight integrated into the pool: it’s controlled by a 315MHz remote. I ordered a 315MHz receiver and transmitter (a few euros on AliExpress…) and I wanted to record the code for each button on the remote with the receiver and then replay them with the transmitter. What do you think?

Thanks in advance for your ideas. Once everything is set up, I’ll share my configuration.

Hello everyone,

After several months, I’m replying to myself.

I’ve almost managed to do everything I wanted (thanks to AI, Claude in this case):

• Integration of the PRIMA START MONO 80 PS (PC1001) heat pump control => OK
• Integration of the 315MHz RGB spotlight control => OK
• Integration of the Davey SilensorPro variable flow pump control => OK
• Integration of temperatures (outside, before heat pump, after heat pump) => OK
• Integration of filter pressure => OK (still need to mount the sensor on the filter)
• Integration of pH and ORP measurements from the PHREDO controllers => OK (needs further testing)

In the following replies, I will detail each point.

The integration of the heat pump was carried out using the SLE118 project on Github, and here is the feedback: https://github.com/sle118/hayward_pool_heater/issues/11 everything works on an ESP8266 dedicated to this purpose.

This integration was incorporated into the project later; I didn’t think I could work with the PAC (which is a 2018 model) as I thought it was too old, but in the end, it worked!

The integration of the 315 MHz RGB spotlight control was achieved by listening to the 315 MHz frames for each button on the remote control and then replaying these frames via a 315 MHz transmitter. Here is the ESPHome code:

# ─────────────────────────────────────────────
# 315 MHz — Émetteur spot LED RGB
# GPIO25
# ─────────────────────────────────────────────
remote_transmitter:
  - id: rc_transmitter
    pin:
      number: GPIO25
    carrier_duty_percent: 100%
    non_blocking: false
# ─────────────────────────────────────────────
# BUTTON — Commande spot LED RGB 315 MHz
# transmit_raw — T=420µs mesuré sur télécommande d'origine
# Format : [bit_burst, bit_silence, ...] + [sync_burst, -sync_silence]
# ─────────────────────────────────────────────
button:
 
  # 010101010101010111001111
  - platform: template
    name: Spotlight On
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 1260,-420, 1260,-420, 420,-1260, 420,-1260, 1260,-420, 1260,-420, 1260,-420, 1260,-420,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010100111100
  - platform: template
    name: Spotlight Off
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 420,-1260, 1260,-420, 1260,-420, 1260,-420, 1260,-420, 420,-1260, 420,-1260,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010111110000
  - platform: template
    name: Spotlight Green
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 1260,-420, 1260,-420, 1260,-420, 1260,-420, 420,-1260, 420,-1260, 420,-1260, 420,-1260,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010100111111
  - platform: template
    name: Spotlight Red
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 420,-1260, 1260,-420, 1260,-420, 1260,-420, 1260,-420, 1260,-420, 1260,-420,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010111000011
  - platform: template
    name: Spotlight Blue
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 1260,-420, 1260,-420, 420,-1260, 420,-1260, 420,-1260, 420,-1260, 1260,-420, 1260,-420,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010100001111
  - platform: template
    name: Spotlight Yellow
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 420,-1260, 420,-1260, 420,-1260, 1260,-420, 1260,-420, 1260,-420, 1260,-420,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010111111100
  - platform: template
    name: Spotlight Cyan
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 1260,-420, 1260,-420, 1260,-420, 1260,-420, 1260,-420, 1260,-420, 420,-1260, 420,-1260,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010111110011
  - platform: template
    name: Spotlight Purple
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 1260,-420, 1260,-420, 1260,-420, 1260,-420, 420,-1260, 420,-1260, 1260,-420, 1260,-420,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010111111111
  - platform: template
    name: Spotlight White
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 1260,-420, 1260,-420, 1260,-420, 1260,-420, 1260,-420, 1260,-420, 1260,-420, 1260,-420,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010111000000
  - platform: template
    name: Spotlight Blue&Cyan
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 1260,-420, 1260,-420, 420,-1260, 420,-1260, 420,-1260, 420,-1260, 420,-1260, 420,-1260,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010100110011
  - platform: template
    name: Spotlight RAINBOW
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 420,-1260, 1260,-420, 1260,-420, 420,-1260, 420,-1260, 1260,-420, 1260,-420,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010100000000
  - platform: template
    name: Spotlight FOUR SEASONS
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 420,-1260, 420,-1260, 420,-1260, 420,-1260, 420,-1260, 420,-1260, 420,-1260,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010101000000
  - platform: template
    name: Spotlight DISCO
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 420,-1260, 420,-1260, 420,-1260, 420,-1260, 420,-1260,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms
 
  # 010101010101010100010000
  - platform: template
    name: Spotlight PARTY
    on_press:
      - remote_transmitter.transmit_raw:
          transmitter_id: rc_transmitter
          code: [420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420, 420,-1260, 1260,-420,
                 420,-1260, 420,-1260, 420,-1260, 1260,-420, 420,-1260, 420,-1260, 420,-1260, 420,-1260,
                 420,-11400]
          repeat:
            times: 5
            wait_time: 40ms

2026-04-25-15h05-34

The variable speed pump control was integrated by listening to Bluetooth frames on an Android phone while using the DAVEY app.

Once the frames were recorded, Claude offered me a directly functional integration (impressive!)…

# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# DEBUT : Gestion de la pompe de circulation de la piscine
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

# ─────────────────────────────────────────────
# BLE — Tracker + Client
# ─────────────────────────────────────────────
esp32_ble_tracker:
  scan_parameters:
    active: false

ble_client:
  - mac_address: "14:2D:41:0D:45:1D"   # Davey Silensor Pro
    id: pompe_silensor
    on_connect:
      then:
        - logger.log: "Pompe connectée — envoi du token d'authentification"
        - delay: 500ms
        - ble_client.ble_write:
            id: pompe_silensor
            service_uuid: "60732856-19e0-43f6-8636-7317571c0000"
            characteristic_uuid: "60732856-19e0-43f6-8636-7317571c0001"
            value: [0xa0, 0x77, 0x58, 0x91, 0x5d, 0xb6]
        - logger.log: "Authentification envoyée"
        - delay: 1000ms
        - select.set:
            id: vitesse_pompe
            option: !lambda 'return id(vitesse_pompe).current_option();'
    on_disconnect:
      then:
        - logger.log: "Pompe déconnectée"

# ─────────────────────────────────────────────
# SWITCH
# ─────────────────────────────────────────────
switch:    
  # Connexion BLE — désactiver pour reprendre la main avec l'app Davey
  - platform: ble_client
    ble_client_id: pompe_silensor
    name: "Connexion BLE pompe"
    id: pompe_connexion

  # Marche/Arrêt pompe
  - platform: template
    name: "Pompe HA ou Prog interne"
    id: pompe_onoff
    icon: mdi:pump
    optimistic: true
    turn_on_action:
      - ble_client.ble_write:
          id: pompe_silensor
          service_uuid: "60732856-19e0-43f6-8636-7317571a0000"
          characteristic_uuid: "60732856-19e0-43f6-8636-7317571a0001"
          value: [0x01]
    turn_off_action:
      - ble_client.ble_write:
          id: pompe_silensor
          service_uuid: "60732856-19e0-43f6-8636-7317571a0000"
          characteristic_uuid: "60732856-19e0-43f6-8636-7317571a0001"
          value: [0x00]
# ─────────────────────────────────────────────
# SELECT — Vitesse pompe par paliers (0% à 90%)
# Valeurs uint16 little-endian extraites du log HCI
# ─────────────────────────────────────────────
select:
  - platform: template
    name: "Vitesse pompe"
    id: vitesse_pompe
    icon: mdi:speedometer
    options:
      - "0%"
      - "10%"
      - "20%"
      - "30%"
      - "40%"
      - "50%"
      - "60%"
      - "70%"
      - "80%"
      - "90%"
    initial_option: "0%"
    optimistic: true
    on_value:
      then:
        - if:
            condition:
              lambda: 'return x == "0%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x00, 0x00]
        - if:
            condition:
              lambda: 'return x == "10%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x0a, 0x00]
        - if:
            condition:
              lambda: 'return x == "20%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x14, 0x00]
        - if:
            condition:
              lambda: 'return x == "30%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x1e, 0x00]
        - if:
            condition:
              lambda: 'return x == "40%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x28, 0x00]
        - if:
            condition:
              lambda: 'return x == "50%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x32, 0x00]
        - if:
            condition:
              lambda: 'return x == "60%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x3c, 0x00]
        - if:
            condition:
              lambda: 'return x == "70%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x46, 0x00]
        - if:
            condition:
              lambda: 'return x == "80%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x50, 0x00]
        - if:
            condition:
              lambda: 'return x == "90%";'
            then:
              - ble_client.ble_write:
                  id: pompe_silensor
                  service_uuid: "60732856-19e0-43f6-8636-7317571d0000"
                  characteristic_uuid: "60732856-19e0-43f6-8636-7317571d2045"
                  value: [0x5a, 0x00]

# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# FIN : Gestion de la pompe de circulation de la piscine
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++

The integration of pH and ORP measurements was performed using an ESP32CAM and an OCR process, which still requires some work to improve reliability, especially during the day when ambient light in the technical room is strong. Once the solution is stable, I will provide a full report here.

For temperature measurements, simple Dallas probes on pipe clamps were used; no need to document this.

Finally, the integration of the filter pressure measurement is still being finalized; the sensor needs to be mounted on the filter, and the mV to bar conversion needs to be established.