5 Commits
0.1.7 ... 0.2.0

5 changed files with 237 additions and 47 deletions

10
CHANGELOG.md Normal file
View File

@@ -0,0 +1,10 @@
# CHANGELOG - Whatsapp Bridge Integration
## Release 0.2.0 - 2026-06-15
- New: Setup of a main device (WhatsApp Bridge Gateway) in the Home Assistant device registry.
- New: Integrated global service `whatsapp_bridge.send_broadcast`, which operates independently of individual profile entities and can send messages to any number or group ID.
- New: Added status sensor (`sensor.whatsapp_bridge_status`). This queries the add-on's new API and provides the current connection status (`CONNECTED`, `WAITING_FOR_SCAN`, `INITIALIZING`, `OFFLINE`) directly within Home Assistant.
- Improved: The sensor is assigned to the new main device, which significantly simplifies automations (e.g., alert on connection loss).
## Release 0.1.7
- Previous stable version

130
README.md
View File

@@ -1,62 +1,112 @@
# WhatsApp Bridge Integration for Home Assistant 🚀
# WhatsApp Bridge for Home Assistant
This is the custom integration for the **Bahmcloud WhatsApp Bridge**. It allows you to manage multiple WhatsApp accounts as Home Assistant services, making it incredibly easy to send automated messages via YAML or Node-RED.
A professional, seamless integration to send WhatsApp messages through the **Bahmcloud Bridge**. This integration supports multiple profiles, dynamic entity-based selection, and broadcast capabilities with native Home Assistant support.
---
## 🚀 Installation
## 🛠️ Installation
### 1. Prerequisite: The Add-on
Before installing this integration, ensure that the **WhatsApp Bridge Add-on** is installed and running.
* [Link to your Add-on Repository]
* Open the Add-on Web UI and scan the QR code to link your WhatsApp account.
### 1. Install the Add-on
The **Bahmcloud WhatsApp Bridge Add-on** must be running for the integration to work:
1. Navigate to **Settings** -> **Add-ons**.
2. Click **Add-on Store** -> Three dots (top right) -> **Repositories**.
3. Add your Bahmcloud Repository URL.
4. Search for "WhatsApp Bridge", click **Install**, and **Start**.
### 2. Install the Integration
1. Copy the folder `whatsapp_bridge_integration` into your Home Assistant `config/custom_components/` directory.
2. Restart Home Assistant.
3. Go to **Settings** -> **Devices & Services**.
4. Click **Add Integration** and search for "WhatsApp Bridge Integration".
You can install the integration component via three methods:
* **HACS (Recommended):** Add this repository as a "Custom Repository" in HACS and click Install.
* **BCS (Bahmcloud Store):** Search for "WhatsApp Bridge" in the BCS interface.
* **Manual:** Copy the `custom_components/whatsapp_bridge_integration` folder into your `/config/custom_components/` directory and restart Home Assistant.
---
## 📖 How to use
## 👥 Configuration & Profiles
Once installed, the integration provides a new service (action) that you can use in any automation.
Add your WhatsApp accounts via the Home Assistant UI:
1. Go to **Settings** -> **Devices & Services**.
2. Click **Add Integration** and search for **WhatsApp Bridge**.
3. Follow the setup to add an **Account Name** (e.g., "Work") and your **Phone Number**.
4. **Repeat** this process for as many accounts as you need.
### Send a Message via YAML
You can call the service directly in your automations:
### Resulting Entities
The integration automatically creates sensors for your UI:
* `sensor.whatsapp_account_name`: An entity for each individual account.
* `sensor.whatsapp_broadcast_all`: A global entity to message all accounts at once.
---
## 🛠 Usage
### Action: `send_message`
This integration registers a service/action to send messages.
**Fields:**
* **Recipient:** Select an account from the dropdown, choose the "Broadcast" entity, or manually type a phone number.
* **Message:** The text content you wish to send.
#### YAML Example:
```yaml
action: whatsapp_bridge_integration.send_message
data:
number: "491701234567"
message: "The washing machine is finished! 🧺"
recipient: "sensor.whatsapp_rene"
message: "The garage door is still open!"
```
### Use in Node-RED
Add a Call Service (or Action) node.
Domain: whatsapp_bridge_integration
Service: send_message
Data:
```JSON
{
"number": "491701234567",
"message": "{{payload}}"
}
```
## 👥 Multi-Account Support (Coming Soon)
We are currently working on a UI-based configuration flow so you can save "Account Aliases" (like "Dad", "Work", "Security") and select them from a dropdown menu without typing the phone number every time.
##⚠️ Important Notes
## ⚠️ Important Notes
Phone Numbers: Always use the international format without + or 00 (e.g., 49... for Germany).
Local Network: The integration communicates locally with the Add-on on port 3000.
Developed by Bahmcloud
---
---
## 🤖 Node-RED Integration
The integration is fully compatible with Node-RED. Since it uses native entities, you can use the standard *Action (Call Service)* node.
### Example: Smart Window Warning
Notify yourself if a window or door has been left open for 15 minutes.
1. *Trigger*: Use a `State Trigger` or `Device` node.
2. *Logic (Change Node)*: Use JSONata to create a dynamic message:
- *Set*: msg.payload
- *Value (JSONata)*: `payload.to_state.attributes.friendly_name & " has been open for 15 minutes!"`
3. WhatsApp Node (Action Node):
- *Action*: `whatsapp_bridge_integration.send_message`
- *Data (JSON)*:
```JSON
{
"recipient": "sensor.whatsapp_broadcast_all",
"message": "{{payload}}"
}
```
### Manual Tool Calling
To send a message to a number not saved as a profile, simply pass the raw phone number to the recipient field in your Node-RED JSON:
```JSON
{
"recipient": "491701234567",
"message": "Direct alert to external number."
}
```
---
# ✨ Features
- *Dynamic UI*: Accounts are automatically added to the recipient dropdown.
- *One-Click Broadcast*: Special entity to reach all configured profiles instantly.
- *Manual Fallback*: Clean UI remains flexible; type any number to bypass profiles.
- *Developer Friendly*: Designed for easy integration with Node-RED and HA Automations.
---
Maintained by Bahmcloud

View File

@@ -1,5 +1,6 @@
import logging
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
@@ -8,11 +9,22 @@ async def async_setup(hass: HomeAssistant, config: dict):
return True
async def async_setup_entry(hass: HomeAssistant, entry):
"""Set up entry and forward to sensor platform."""
"""Set up entry, create general device and forward to sensor platform."""
# Lege die Daten im hass-Objekt ab
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = entry.data
# 1. Hauptgerät (General Device) im Device Registry anlegen
device_registry = dr.async_get(hass)
device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
identifiers={(DOMAIN, "general_gateway")},
name="WhatsApp Bridge Gateway",
manufacturer="Bahmcloud",
model="Bridge Server v0.2.0",
sw_version="0.2.0",
)
# Forward the setup to the sensor platform to create entities
await hass.config_entries.async_forward_entry_setups(entry, ["sensor"])

View File

@@ -4,7 +4,7 @@
"documentation": "https://git.bahmcloud.de/bahmcloud/Whatsapp-Bridge-Integration",
"dependencies": [],
"codeowners": ["@bahmcloud"],
"version": "0.1.7",
"version": "0.2.0",
"iot_class": "local_polling",
"config_flow": true
}

View File

@@ -1,18 +1,62 @@
import logging
import async_timeout
import aiohttp
from datetime import timedelta
from homeassistant.components.sensor import SensorEntity
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
# Polling-Intervall (15 Sekunden)
SCAN_INTERVAL = timedelta(seconds=15)
async def async_setup_entry(hass, entry, async_add_entities):
"""Add sensors for WhatsApp accounts and a global broadcast sensor."""
entities = [WhatsAppAccountEntity(entry)]
"""Add sensors for WhatsApp accounts, live status, and a global broadcast sensor."""
# Wir prüfen, ob die Broadcast-Entität schon existiert
# Falls nicht, legen wir sie einmalig an
# Coordinator für den echten Live-Status vom Add-on einrichten
async def _async_update_data():
url = "http://866fd2eb-whatsapp-bridge:3000/api/status"
async with aiohttp.ClientSession() as session:
try:
async with async_timeout.timeout(5):
async with session.get(url) as response:
if response.status != 200:
raise UpdateFailed(f"API meldet Fehler {response.status}")
return await response.json()
except Exception as err:
raise UpdateFailed(f"Add-on nicht erreichbar: {err}")
coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
name="whatsapp_bridge_status",
update_method=_async_update_data,
update_interval=SCAN_INTERVAL,
)
# Ersten Abruf vor dem Erstellen der Entitäten erzwingen
try:
await coordinator.async_config_entry_first_refresh()
except UpdateFailed:
_LOGGER.warning("Erster Status-Abruf fehlgeschlagen. Add-on läuft eventuell noch an.")
# Basis-Entitäten: Account-Sensor und der neue Live-Status-Sensor
entities = [
WhatsAppAccountEntity(entry),
WhatsAppStatusSensor(coordinator, entry)
]
# Prüfen, ob die Broadcast-Entität schon existiert
if not hass.data[DOMAIN].get("broadcast_registered"):
entities.append(WhatsAppBroadcastEntity())
hass.data[DOMAIN]["broadcast_registered"] = True
async_add_entities(entities, True)
class WhatsAppAccountEntity(SensorEntity):
"""Individual Account (e.g., Rene, Work)."""
def __init__(self, entry):
@@ -29,6 +73,14 @@ class WhatsAppAccountEntity(SensorEntity):
def state(self):
return "Ready"
@property
def device_info(self) -> DeviceInfo:
"""Ordnet diesen Sensor dem Hauptgerät zu."""
return DeviceInfo(
identifiers={(DOMAIN, "general_gateway")},
)
class WhatsAppBroadcastEntity(SensorEntity):
"""Virtual 'All Accounts' Entity."""
def __init__(self):
@@ -41,4 +93,70 @@ class WhatsAppBroadcastEntity(SensorEntity):
@property
def state(self):
return "Global"
return "Global"
@property
def device_info(self) -> DeviceInfo:
"""Ordnet diesen Sensor dem Hauptgerät zu."""
return DeviceInfo(
identifiers={(DOMAIN, "general_gateway")},
)
class WhatsAppStatusSensor(SensorEntity):
"""Echter Live-Status-Sensor, gekoppelt an die Add-on API."""
def __init__(self, coordinator, entry):
self.coordinator = coordinator
self._entry = entry
self._attr_name = "WhatsApp Bridge Status"
self._attr_unique_id = f"{entry.entry_id}_bridge_live_status"
self._attr_icon = "mdi:whatsapp"
@property
def should_poll(self) -> bool:
return False
@property
def available(self) -> bool:
return self.coordinator.last_update_success
@property
def state(self):
"""Gibt den dynamischen Status aus der Add-on API zurück."""
data = self.coordinator.data
if not data:
return "OFFLINE"
if data.get("isReady"):
return "CONNECTED"
elif data.get("hasQr"):
return "WAITING_FOR_SCAN"
elif data.get("isInitializing"):
return "INITIALIZING"
return "UNKNOWN"
@property
def extra_state_attributes(self):
"""Zusätzliche Attribute für erweitertes Debugging."""
data = self.coordinator.data
if data:
return {
"client_state": data.get("clientState", "UNKNOWN"),
"has_qr_code": data.get("hasQr", False)
}
return {}
@property
def device_info(self) -> DeviceInfo:
"""Ordnet diesen Sensor dem Hauptgerät zu."""
return DeviceInfo(
identifiers={(DOMAIN, "general_gateway")},
)
async def async_added_to_hass(self):
"""Registrieren beim Live-Coordinator."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)