Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 26 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Add this to your Lovelace dashboard:
type: custom:zigbee-floorplan-card
entity: sensor.zigbee2mqtt_networkmap
image: /local/floorplan.png
device_coordinates:
devices:
"0xbc026efffe29c7de": { x: 500, y: 400 } # Coordinator
"0x001788010d5caf75": { x: 200, y: 200 } # Living Room Light
# ... more devices
Expand All @@ -156,12 +156,10 @@ circle_radius: 10
show_labels: true
show_link_lqi: false
mqtt_base_topic: zigbee2mqtt
device_coordinates:
"0xbc026efffe29c7de": { x: 500, y: 400 }
"0x001788010d5caf75": { x: 200, y: 200 }
devices:
"0xbc026efffe29c7de": { x: 500, y: 400, name: "Coordinator" }
"0x001788010d5caf75": { x: 200, y: 200, name: "Living Room Light" }
"0x00158d0001a2b3c4": { x: 700, y: 300 }
friendly_names:
"0x001788010d5caf75": "Living Room Light (Override)"
```

See [configuration-example.yaml](examples/configuration-example.yaml) for more examples.
Expand All @@ -172,16 +170,13 @@ See [configuration-example.yaml](examples/configuration-example.yaml) for more e
|--------|------|----------|---------|-------------|
| `entity` | string | **Yes** | - | Entity ID of the MQTT network map sensor |
| `image` | string | **Yes** | - | Path to floorplan image (e.g., `/local/floorplan.png`) |
| `device_coordinates` | object | **Yes** | - | Map of IEEE addresses to x,y coordinates |
| `devices` | object | **Yes** | - | Map of IEEE addresses to `x`, `y` coordinates and optional `name` override |
| `image_width` | number | No | 1000 | Width of the floorplan image in pixels |
| `image_height` | number | No | 800 | Height of the floorplan image in pixels |
| `circle_radius` | number | No | 10 | Radius of device circles in pixels |
| `show_labels` | boolean | No | true | Show device labels |
| `show_link_lqi` | boolean | No | false | Show link quality values on connections |
| `mqtt_base_topic` | string | No | zigbee2mqtt | Zigbee2MQTT MQTT base topic |
| `friendly_names` | object | No | {} | Manual device name overrides |
| `auto_friendly_names` | boolean | No | true | Automatically lookup friendly names from Home Assistant entities |
| `friendly_names` | object | No | {} | Map of IEEE addresses to friendly names (overrides auto-lookup) |

## Getting Device IEEE Addresses

Expand Down Expand Up @@ -282,10 +277,13 @@ The card falls back to showing the last 4 characters of the IEEE address when it

1. **Check browser console** (F12) - Look for `[Zigbee Floorplan]` messages
2. **Verify entity attributes** - Go to Developer Tools → States, find your devices and check if they have `ieee_address` attribute
3. **Try manual names** - Add the device to `friendly_names` configuration:
3. **Try manual names** - Add a `name` field to the device entry in `devices`:
```yaml
friendly_names:
'0xbc026efffe29c7de': 'My Device Name'
devices:
'0xbc026efffe29c7de':
x: 500
y: 400
name: 'My Device Name'
```
4. **Enable debug logging** - The console will show which devices were found and which weren't

Expand All @@ -305,35 +303,26 @@ The card falls back to showing the last 4 characters of the IEEE address when it

### Auto-Friendly Names

By default, the card automatically looks up friendly names from Home Assistant entities. The lookup priority is:
By default, the card automatically looks up friendly names from the Zigbee2MQTT network map data. The lookup priority is:

1. **Manual override**: Names specified in `friendly_names` config
2. **Entity attributes**: Searches for entities with matching `ieee_address` attribute
1. **Name field in coordinates**: `name` specified alongside `x`/`y` in `devices`
2. **Network map data**: Friendly name from Zigbee2MQTT included in the entity attributes
3. **Fallback**: Last 4 characters of IEEE address

To disable automatic lookup:
```yaml
auto_friendly_names: false
```

### Manual Friendly Name Override

You can manually specify names that will override the auto-lookup:

```yaml
friendly_names:
'0xbc026efffe29c7de': 'Main Coordinator' # Overrides auto-detected name
'0x001788010d5caf75': 'Living Room Plug'
```

### Dynamic Friendly Names

You can use Home Assistant entity names as friendly names:
You can specify a name per device directly in `devices`:

```yaml
friendly_names:
'0xbc026efffe29c7de': 'Coordinator'
'0x001788010d5caf75': '{{ states("sensor.living_room_router") }}'
devices:
'0xbc026efffe29c7de':
x: 500
y: 400
name: 'Main Coordinator'
'0x001788010d5caf75':
x: 200
y: 200
name: 'Living Room Plug'
```

### Multiple Floors
Expand All @@ -345,13 +334,13 @@ Create separate cards for each floor with different floorplan images:
entity: sensor.zigbee_coordinator_networkmap
image: /local/floor1.png
title: First Floor
device_coordinates: { ... }
devices: { ... }

- type: custom:zigbee-floorplan-card
entity: sensor.zigbee_coordinator_networkmap
image: /local/floor2.png
title: Second Floor
device_coordinates: { ... }
devices: { ... }
```

### Custom Styling
Expand Down
6 changes: 3 additions & 3 deletions docs/MQTT-SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Update your card configuration to use the new sensor:
type: custom:zigbee-floorplan-card
entity: sensor.zigbee2mqtt_networkmap # The MQTT sensor
image: /local/floorplan.png
device_coordinates:
devices:
"0x00124b001234abcd": { x: 500, y: 400 } # Coordinator
"0x00124b005678efgh": { x: 300, y: 200 } # Living Room Light
# Add more devices...
Expand All @@ -143,7 +143,7 @@ type: custom:zigbee-floorplan-card
entity: sensor.zigbee2mqtt_networkmap
image: /local/floorplan.png
mqtt_base_topic: my_custom_topic # Default is 'zigbee2mqtt'
device_coordinates:
devices:
# ...
```

Expand All @@ -155,7 +155,7 @@ You can still override individual device names:
type: custom:zigbee-floorplan-card
entity: sensor.zigbee2mqtt_networkmap
image: /local/floorplan.png
device_coordinates:
devices:
# ...
friendly_names:
"0x00124b005678efgh": "My Custom Name" # Override the Z2M name
Expand Down
7 changes: 3 additions & 4 deletions docs/PROJECT-INFO.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ Minimal configuration:
type: custom:zigbee-floorplan-card
entity: sensor.zigbee2mqtt_networkmap
image: /local/floorplan.png
device_coordinates:
devices:
'0xYOURDEVICEADDRESS':
x: 500
y: 400
Expand All @@ -172,12 +172,11 @@ circle_radius: 10
show_labels: true
show_link_lqi: false # Show LQI numbers on connections (default: false)
mqtt_base_topic: zigbee2mqtt
friendly_names: # Optional overrides
'0xbc026efffe29c7de': 'Main Coordinator'
device_coordinates:
devices:
'0xbc026efffe29c7de':
x: 500
y: 400
name: 'Coordinator'
'0x001788010d5caf75':
x: 200
y: 200
Expand Down
6 changes: 3 additions & 3 deletions docs/QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ Example: `0x00124b001234abcd`
type: custom:zigbee-floorplan-card
entity: sensor.zigbee2mqtt_networkmap
image: /local/floorplan.png
device_coordinates:
devices:
"0x00124b001234abcd": { x: 500, y: 400 } # Coordinator
"0x00124b005678efgh": { x: 300, y: 200 } # Living Room Light
"0x00124b009abcdef0": { x: 700, y: 300 } # Bedroom Sensor
Expand Down Expand Up @@ -146,7 +146,7 @@ Add these options to your card configuration:
type: custom:zigbee-floorplan-card
entity: sensor.zigbee2mqtt_networkmap
image: /local/floorplan.png
device_coordinates:
devices:
# ... your devices ...

# Optional customization
Expand Down Expand Up @@ -175,7 +175,7 @@ Make your device names readable:
- Check that sensor name is `sensor.zigbee2mqtt_networkmap`

**No devices showing**
- Check `device_coordinates` has correct IEEE addresses
- Check `devices` has correct IEEE addresses
- Verify coordinates are within image bounds

**Device names show as codes**
Expand Down
15 changes: 5 additions & 10 deletions examples/card-config-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,26 @@ show_labels: true # Show device labels (optional, default: true)
show_link_lqi: false # Show link quality indicator (LQI value) on connections (optional, default: false)
mqtt_base_topic: zigbee2mqtt # MQTT base topic for Zigbee2MQTT (optional, default: 'zigbee2mqtt')

# Friendly names for devices (optional - overrides auto-lookup)
# The card automatically uses friendly names from the Zigbee2MQTT network map data.
# Only add entries here if you want to override specific device names.
# Use IEEE addresses (lowercase) as keys.
friendly_names:
'0xbc026efffe29c7de': 'Main Coordinator'
'0x001788010d5caf75': 'Living Room Router'
'0x881a14fffefeab2d': 'Kitchen Router'

# Device coordinates (x, y in pixels) - REQUIRED
# Map each device's IEEE address to its position on your floorplan image.
# Use lowercase for IEEE addresses to match the code's normalization.
device_coordinates:
# Add an optional 'name' field to override the auto-detected friendly name.
devices:
# Coordinator (center of house)
'0xbc026efffe29c7de':
x: 500
y: 400
name: 'Main Coordinator'

# Routers (distributed throughout)
'0x001788010d5caf75':
x: 200
y: 200
name: 'Living Room Router'
'0x881a14fffefeab2d':
x: 800
y: 200
name: 'Kitchen Router'
'0x8c65a3fffe1050a0':
x: 200
y: 600
Expand Down
4 changes: 2 additions & 2 deletions examples/configuration-example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ automation:
type: custom:zigbee-floorplan-card
entity: sensor.zigbee2mqtt_networkmap
image: /local/floorplan.png
device_coordinates:
devices:
# Replace these IEEE addresses with your actual device addresses
"0x00124b001234abcd": { x: 500, y: 400 } # Coordinator
"0x00124b005678efgh": { x: 300, y: 200 } # Living Room Light
Expand All @@ -65,7 +65,7 @@ type: custom:zigbee-floorplan-card
# Required settings
entity: sensor.zigbee2mqtt_networkmap
image: /local/floorplan.png
device_coordinates:
devices:
"0x00124b001234abcd": { x: 500, y: 400 }
"0x00124b005678efgh": { x: 300, y: 200 }
"0x00124b009abcdef0": { x: 700, y: 300 }
Expand Down
2 changes: 1 addition & 1 deletion tools/coordinate-picker.html
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ <h3>Generated YAML Configuration:</h3>
mqtt_base_topic: zigbee2mqtt

# Device coordinates
device_coordinates:\n`;
devices:\n`;
devices.forEach(d => {
yaml += ` '${d.address}':\n x: ${d.x}\n y: ${d.y}\n`;
});
Expand Down
30 changes: 15 additions & 15 deletions zigbee-floorplan-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class ZigbeeFloorplanCard extends HTMLElement {
if (!config.image) {
throw new Error('You need to define an image');
}
if (!config.device_coordinates) {
throw new Error('You need to define device_coordinates');
if (!config.devices) {
throw new Error('You need to define devices');
}

// Validate and sanitize config values
Expand All @@ -32,13 +32,12 @@ class ZigbeeFloorplanCard extends HTMLElement {
this._config = {
entity: this._sanitizeString(config.entity),
image: this._sanitizeUrl(config.image),
device_coordinates: config.device_coordinates,
devices: config.devices,
Comment on lines 20 to +35
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setConfig now requires config.devices and will throw for existing configurations that still use the documented device_coordinates key from prior versions. To avoid a breaking change (or at least provide a smoother migration), consider accepting device_coordinates as a fallback/alias (and/or emitting a clear deprecation warning) before throwing an error.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can live with that. I will bump the mayor version.

image_width: imageWidth,
image_height: imageHeight,
circle_radius: circleRadius,
show_labels: config.show_labels !== false,
show_link_lqi: config.show_link_lqi === true,
friendly_names: config.friendly_names || {},
mqtt_base_topic: this._sanitizeString(config.mqtt_base_topic || 'zigbee2mqtt')
};
Comment on lines 32 to 42
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change removes friendly_names support entirely (it is no longer stored on _config and getDeviceLabel no longer checks it). That’s a breaking config change for existing users; consider supporting friendly_names as a deprecated fallback by mapping entries into devices[ieee].name (or, at minimum, detect friendly_names and surface a targeted migration error/warning).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can live with that. I will bump the mayor version.

}
Expand Down Expand Up @@ -544,8 +543,8 @@ class ZigbeeFloorplanCard extends HTMLElement {
}
processedLinks.add(linkKey);

const sourceCoords = this._config.device_coordinates[sourceAddr];
const targetCoords = this._config.device_coordinates[targetAddr];
const sourceCoords = this._config.devices[sourceAddr];
const targetCoords = this._config.devices[targetAddr];

if (sourceCoords && targetCoords) {
const lqi = link.lqi || link.linkquality || 0;
Expand Down Expand Up @@ -600,9 +599,9 @@ class ZigbeeFloorplanCard extends HTMLElement {

nodes.forEach(node => {
const ieeeAddr = node.ieeeAddr;
const coords = this._config.device_coordinates[ieeeAddr];
const device = this._config.devices[ieeeAddr];

if (coords) {
if (device) {
const deviceType = node.type || 'EndDevice'; // Coordinator, Router, EndDevice
const deviceClass = deviceType === 'Coordinator' ? 'coordinator' :
deviceType === 'Router' ? 'router' : 'end-device';
Expand All @@ -611,8 +610,8 @@ class ZigbeeFloorplanCard extends HTMLElement {
// Draw circle
svgDevices.push(`
<circle
cx="${parseFloat(coords.x)}"
cy="${parseFloat(coords.y)}"
cx="${parseFloat(device.x)}"
cy="${parseFloat(device.y)}"
r="${parseInt(this._config.circle_radius)}"
class="device-circle ${deviceClass} ${isSelected ? 'selected' : ''}"
data-ieee="${this._escapeHtml(String(ieeeAddr))}"
Expand All @@ -626,8 +625,8 @@ class ZigbeeFloorplanCard extends HTMLElement {
const safeLabel = this._escapeHtml(String(label));
svgDevices.push(`
<text
x="${parseFloat(coords.x)}"
y="${parseFloat(coords.y) + parseInt(this._config.circle_radius) + 15}"
x="${parseFloat(device.x)}"
y="${parseFloat(device.y) + parseInt(this._config.circle_radius) + 15}"
class="device-label"
text-anchor="middle"
style="pointer-events: none;"
Expand All @@ -641,9 +640,10 @@ class ZigbeeFloorplanCard extends HTMLElement {
}

getDeviceLabel(ieeeAddr, friendlyName) {
// Priority 1: Manual override from config
if (this._config.friendly_names && this._config.friendly_names[ieeeAddr]) {
return this._config.friendly_names[ieeeAddr];
// Priority 1: Name field in devices config
const device = this._config.devices && this._config.devices[ieeeAddr];
if (device && device.name) {
return device.name;
}

// Priority 2: Friendly name from Zigbee2MQTT network map
Expand Down
Loading