A Home Assistant custom integration for FMD (Find My Device) that allows you to track and control Android devices running the FMD app through your self-hosted FMD server.
FMD (Find My Device) is a free and open source device tracking solution created by Nulide and maintained by the FMD-FOSS team.
- FMD Android App: https://gitlab.com/fmd-foss/fmd-android
- FMD Server: https://gitlab.com/fmd-foss/fmd-server
- Website: https://fmd-foss.org
This integration acts as a full client for your FMD server, providing seamless integration with Home Assistant. See CREDITS.md for full attribution. It uses fmd_api, which was written purpose-built for this integration to be able to interact with the FMD server.
This integration provides 22 entities to control your Android device:
πΊοΈ Location Tracking
- Real-time device location on Home Assistant map
- Multiple location providers (GPS, network, fused, cell)
- Configurable accuracy filtering
- On-demand location updates
π± Remote Commands
- Ring device at max volume
- Lock device remotely
- Toggle Bluetooth on/off
- Control Do Not Disturb mode
- Change ringer mode (Normal/Vibrate/Silent)
- Factory reset with safety protection
πΈ Photo Capture
- Remote camera control (front & rear)
- Automatic photo download to media library
- EXIF timestamp extraction
- Media browser integration
βοΈ Smart Tracking
- Normal polling mode (configurable interval)
- High-frequency active tracking mode
- Battery-conscious location source selection
- GPS only, Cell only, or Last Known options
Before installing this integration, you need:
- β Home Assistant (2023.1 or newer recommended)
- β
FMD Server (v0.13.0 recommended)
- Self-hosted or hosted instance
- HTTPS recommended for security; HTTP also supported (via fmd-api 2.0.9+)
- FMD server must be accessible from Home Assistant
- Compatibility: This integration is designed to maintain compatibility with fmd-server.
- It has been tested with versions 0.11.0, 0.12.0, 0.12.1, and 0.13.0.
- It seeks to maintain compatibility with the latest versions of fmd-server but cannot guarantee backwards compatibility.
- β
Android Device with FMD app installed
- Android 7.0 or newer
- FMD app from F-Droid or GitLab
- Android device connect to a self-hosted or hosted FMD server
- β
FMD Account Credentials
- Device ID (from FMD app settings)
- Password (set when registering device)
- Bluetooth Control: Android 12+ with BLUETOOTH_CONNECT permission
- DND/Ringer Control: Do Not Disturb Access permission granted to FMD app
- Device Wipe: Device Admin permission granted to FMD app
- Photos: Camera permissions granted to FMD app
- β User access to the FMD server - this integration connects directly to the FMD API
- β Public IP address (works on your local network if you are self-hosting FMD)
- β Cloud services (fully self-hosted)
You can install via the HACS Default store (once approved), or add as a Custom Repository today.
- Open HACS in Home Assistant
- Click the + button and search for "FMD"
- Click "Download" and restart Home Assistant
- Open HACS in Home Assistant
- Click the three dots in the top right corner and select Custom repositories
- Add this repository URL:
https://github.com/devinslick/home-assistant-fmd - Select Integration as the category
- Click Add
- Click the "+" button in HACS
- Search for "FMD" or "Find My Device"
- Click "Download"
- Restart Home Assistant
- Copy the
custom_components/fmddirectory to your Home Assistantcustom_componentsdirectory. - Restart Home Assistant.
- Go to Settings -> Devices & Services.
- Click Add Integration.
- Search for "FMD" and select it.
- Enter your FMD server URL, ID, and password.
- Configure the polling interval (in minutes) and location accuracy filtering.
- Allow inaccurate locations (default: disabled) - When unchecked, filters out low-accuracy location updates from providers like BeaconDB. By default only Fused, GPS, and network locations will be accepted.
- Use imperial units (default: disabled) - When checked, converts metric measurements to imperial (meters β feet, m/s β mph)
- Click Submit.
The integration will create the following entities for each configured FMD device:
- Device Tracker - Displays the current location of your device on the map
- Entity ID example:
device_tracker.fmd_test_user - Updates automatically based on the configured polling interval
- Shows latitude, longitude, and other location metadata
- Attributes:
battery_level- Device battery percentage (0-100)provider- Location provider used by the device (e.g.,fused,gps,network,BeaconDB)last_poll_time- ISO timestamp when Home Assistant last polled the FMD serverdevice_timestamp- Human-readable timestamp when the device sent the location to FMD serverdevice_timestamp_ms- Unix timestamp (milliseconds) when the device sent the location to FMD servergps_accuracy- GPS accuracy in meters (or feet if imperial units enabled)gps_accuracy_unit- Unit of measurement for GPS accuracy ("m" or "ft")altitude- Altitude in meters (or feet if imperial units enabled)altitude_unit- Unit of measurement for altitude ("m" or "ft")speed- Speed in meters per second (or mph if imperial units enabled)speed_unit- Unit of measurement for speed ("m/s" or "mph")heading- Direction/bearing in degrees 0-360Β° (optional - only present when device is moving)
- Entity ID example:
-
Update Interval - Set the standard polling interval (1-1440 minutes, default: 30)
- Entity ID example:
number.fmd_test_user_update_interval - Controls how frequently the integration checks for location updates in normal mode
- β Changes take effect immediately - No reload required!
- Entity ID example:
-
High Frequency Interval - Set the high-frequency polling interval (1-60 minutes, default: 5)
- Entity ID example:
number.fmd_test_user_high_frequency_interval - Controls the polling rate when High Frequency Mode is enabled
- β Changes take effect immediately - If high-frequency mode is active, the new interval is applied right away
- Entity ID example:
-
Photo: Max to retain - Set maximum photos to keep in media folder (1-50, default: 10)
- Entity ID example:
number.fmd_test_user_max_photos - Controls retention limit for automatic cleanup
- When "Photo: Auto-cleanup" is enabled, oldest photos are deleted after download if total exceeds this limit
- Also controls how many photos are fetched from server (downloads N most recent)
- Entity ID example:
-
Location Update - Request a new location from the device
- Entity ID example:
button.fmd_test_user_location_update - Sends a command to the FMD device to capture a new location using all available providers (Fused, GPS, network, cell)
- Waits 10 seconds for the device to respond, then fetches the updated location from the server
- Entity ID example:
-
Volume: Ring device - Make the device ring at maximum volume
- Entity ID example:
button.fmd_test_user_ring - Sends a ring command to the device, making it play a loud sound
- Useful for finding a lost device nearby
- Entity ID example:
-
Lock device - Lock the device screen
- Entity ID example:
button.fmd_test_user_lock - Sends a lock command to secure the device
- Optional message support: Set "Lock: Message" text entity to display a message on the lock screen
- Example use: "Lost phone - please call 555-1234" or contact information
- Client automatically sanitizes message for safety
- Useful if device is lost or stolen
- Entity ID example:
-
Photo: Capture front - Take a photo with the front-facing camera
- Entity ID example:
button.fmd_test_user_capture_front - Sends a "camera front" command to the device
- Device captures photo and uploads to FMD server (~15-30 seconds)
- Press "Photo: Download" button afterwards to retrieve the photo
- Entity ID example:
-
Photo: Capture rear - Take a photo with the rear-facing camera
- Entity ID example:
button.fmd_test_user_capture_rear - Sends a "camera back" command to the device
- Device captures photo and uploads to FMD server (~15-30 seconds)
- Press "Photo: Download" button afterwards to retrieve the photo
- Entity ID example:
-
Photo: Download - Download photos from server to media folder
- Entity ID example:
button.fmd_test_user_download_photos - Fetches the N most recent photos from server (N = "Max Photos to Download" setting)
- Decrypts and saves photos to
/config/media/fmd/device_namefolder - Photos automatically appear in Home Assistant's Media Browser
- Updates the "Photo Count" sensor
- Entity ID example:
-
Wipe:
β οΈ Executeβ οΈ -β οΈ DANGEROUS: Factory reset the device (erases ALL data)- Entity ID example:
button.fmd_test_user_wipe_device - Requirements:
- "Wipe:
β οΈ Safety switchβ οΈ " must be enabled first - "Wipe: PIN" must be set with a valid alphanumeric PIN
- "Wipe:
- Validates PIN before sending wipe command (alphanumeric ASCII, no spaces)
- Always passes confirmation flag to prevent accidental execution
β οΈ THIS CANNOT BE UNDONE - All data on device will be permanently erased- Safety switch automatically disables after use to prevent accidental repeated presses
- Icon:
mdi:delete-foreverto indicate destructive action
- Entity ID example:
-
High Frequency Mode - Enable active tracking with device location requests
- Entity ID example:
switch.fmd_test_user_high_frequency_mode - When enabled:
- Immediately requests a new location from the device
- Switches to high-frequency polling interval
- Each poll requests fresh location data from the device using the selected Location Source
- When disabled, returns to normal polling interval
β οΈ Battery impact: Active tracking drains device battery faster- Useful for tracking during active travel, emergencies, or finding lost devices
- Entity ID example:
-
Location: allow inaccurate updates - Toggle location filtering
- Entity ID example:
switch.fmd_test_user_allow_inaccurate - When off (default): Blocks location updates from low-accuracy providers (e.g., BeaconDB). Only accepts updates from accurate providers (Fused, GPS, and network).
- When on: Accepts all location updates regardless of provider accuracy.
- Note: You can also configure this during initial setup via the config flow.
- Entity ID example:
-
Photo: Auto-cleanup - Automatic deletion of old photos
- Entity ID example:
switch.fmd_test_user_photo_auto_cleanup - When on: Automatically deletes oldest photos after download if total exceeds "Photo: Max to retain" limit
- When off (default): Photos are never automatically deleted
- Deletion is based on file modification time (oldest first)
β οΈ Warning: Deleted photos cannot be recovered
- Entity ID example:
-
Wipe:
β οΈ Safety switchβ οΈ - Safety switch for device wipe command- Entity ID example:
switch.fmd_test_user_device_wipe_safety - Must be enabled before the "Wipe:
β οΈ Executeβ οΈ " button will function β οΈ Automatically disables after 60 seconds for safetyβ οΈ DANGEROUS: Only enable if you intend to wipe the device- Icon:
mdi:alert-octagonto indicate danger
- Entity ID example:
-
Location Source - Choose which location provider the Location Update button uses
- Entity ID example:
select.fmd_test_user_location_source - Options: "All Providers (Default)", "GPS Only (Accurate)", "Cell Only (Fast)", "Last Known (No Request)"
- All Providers: Uses GPS, network, and fused location (most reliable)
- GPS Only: Best accuracy but slower, requires clear sky view
- Cell Only: Fast but less accurate, uses cellular towers
- Last Known: Returns cached location without new GPS request (instant, no battery use)
- Selection persists and is used by the Location Update button
- Entity ID example:
-
Bluetooth - Send Bluetooth enable/disable commands
- Entity ID example:
select.fmd_test_user_bluetooth_command - Options: "Send Command...", "Enable Bluetooth", "Disable Bluetooth"
- Sends command to device, then resets to "Send Command..." placeholder
β οΈ Requires Android 12+ BLUETOOTH_CONNECT permission
- Entity ID example:
-
Volume: Do Not Disturb - Send DND enable/disable commands
- Entity ID example:
select.fmd_test_user_do_not_disturb_command - Options: "Send Command...", "Enable Do Not Disturb", "Disable Do Not Disturb"
- Sends command to device, then resets to placeholder
β οΈ Requires Do Not Disturb Access permission
- Entity ID example:
-
Volume: Ringer mode - Set device ringer mode
- Entity ID example:
select.fmd_test_user_ringer_mode_command - Options: "Send Command...", "Normal (Sound + Vibrate)", "Vibrate Only", "Silent"
- Sends command to device, then resets to placeholder
β οΈ Requires Do Not Disturb Access permissionβ οΈ Note: Silent mode also enables Do Not Disturb (Android behavior)
- Entity ID example:
-
Wipe: PIN - Alphanumeric PIN required for device wipe command
- Entity ID example:
text.fmd_test_user_wipe_pin - Required for wipe operation - Must be set before "Wipe:
β οΈ Executeβ οΈ " button will work - Validation requirements:
- Must be alphanumeric (letters and numbers only)
- Cannot contain spaces
- Must contain only ASCII characters
- Password-mode text input (masked in UI for security)
β οΈ Note: Current FMD server versions require 8+ character PINs for new accounts- Stored securely in config entry
- Icon:
mdi:key-variant
- Entity ID example:
-
Lock: Message - Optional message to display on locked device screen
- Entity ID example:
text.fmd_test_user_lock_message - Optional - If set, message will be shown when device is locked
- Plain text input (max 500 characters)
- Client automatically sanitizes dangerous characters for safety
- Useful for contact information or instructions (e.g., "Lost phone - call 555-1234")
- Icon:
mdi:message-text-lock
- Entity ID example:
- Photo count - Total number of photos stored in media folder
- Entity ID example:
sensor.fmd_test_user_photo_count - Shows total
.jpgfiles currently in/config/media/fmd/ - Attributes:
last_download_count- Number of photos downloaded in the last operationlast_download_time- ISO timestamp of the last photo downloadphotos_in_media_folder- Same as main value (kept for backward compatibility)
- Entity ID example:
All entities are grouped together under a single FMD device in Home Assistant (e.g., "FMD test-user").
For a user with FMD account ID test-user, the following entities will be created:
Device Tracker:
device_tracker.fmd_test_user- Device location tracker
Number Entities (3):
2. number.fmd_test_user_update_interval - Standard polling interval setting
3. number.fmd_test_user_high_frequency_interval - High-frequency polling interval setting
4. number.fmd_test_user_max_photos - Max photos to download setting
Button Entities (7):
5. button.fmd_test_user_location_update - Location update trigger
6. button.fmd_test_user_ring - Ring device trigger
7. button.fmd_test_user_lock - Lock device trigger
8. button.fmd_test_user_capture_front - Capture front camera photo
9. button.fmd_test_user_capture_rear - Capture rear camera photo
10. button.fmd_test_user_download_photos - Download photos from server
11. button.fmd_test_user_wipe_device -
Switch Entities (4):
12. switch.fmd_test_user_high_frequency_mode - High-frequency mode toggle
13. switch.fmd_test_user_allow_inaccurate - Location accuracy filter toggle
14. switch.fmd_test_user_photo_auto_cleanup - Photo: Auto-cleanup toggle
15. switch.fmd_test_user_device_wipe_safety - Safety switch for device wipe
Select Entities (4):
16. select.fmd_test_user_location_source - Location provider selection
17. select.fmd_test_user_bluetooth_command - Bluetooth enable/disable commands
18. select.fmd_test_user_do_not_disturb_command - DND enable/disable commands
19. select.fmd_test_user_ringer_mode_command - Ringer mode commands
Text Entities (2):
20. text.fmd_test_user_wipe_pin - Wipe PIN (required for device wipe)
21. text.fmd_test_user_lock_message - Lock message (optional for lock command)
Sensor Entities (1):
22. sensor.fmd_test_user_photo_count - Total stored photos on server
Total: 22 entities per device
Note: Hyphens in your FMD account ID will be converted to underscores in entity IDs.
- Dynamic polling interval updates - Changes take effect immediately without restart
- High-frequency active-tracking mode - Requests fresh device location at faster intervals (battery intensive)
- Location update button - Triggers immediate on-demand location update from device
- Configurable location source - Choose between All Providers, GPS Only, Cell Only, or Last Known location
- Location accuracy filtering - Filters inaccurate providers (BeaconDB) while accepting accurate ones (Fused, GPS, network)
- Location metadata attributes - Tracks GPS accuracy, altitude, speed, and heading
- Ring button - Makes device play loud sound at maximum volume
- Lock button - Remotely locks the device screen
- Multiple location provider support - Fused (Android's best), GPS, network, and cell tower
- Smart location selection - Checks up to 5 recent locations to find most recent accurate one
- Photo capture - Remote front and rear camera photo capture
- Photo download - Download and decrypt photos from FMD server
- Media browser integration - Photos automatically appear in Home Assistant's media browser
- Configurable photo downloads - Set how many recent photos to download (1-50)
- EXIF timestamp extraction - Photos named with capture date/time for chronological sorting
- Bluetooth control - Send enable/disable Bluetooth commands to device
- Do Not Disturb control - Send enable/disable DND commands to device
- Ringer mode control - Set device ringer to Normal, Vibrate, or Silent mode
- Device wipe - Factory reset device with safety switch protection (60-second timeout)
Normal Mode (default: 15 minutes)
- Minimal battery drain on device
- Queries FMD server for existing location data
- Does NOT request new device location from the android device
- Recommended for stationary devices and those that are sensitive to battery drain
High Frequency Mode (default: 5 minutes)
β οΈ Higher battery drain - requests new location each poll- Actively asks device for new location information from a configured source
- Best for: lost device tracking, active travel while charging
- Auto-disable after tracking session
| Feature | Battery Impact | When to Use |
|---|---|---|
| Normal polling | β‘ Minimal | Always |
| High frequency mode | β‘β‘β‘ High | Lost device, active tracking |
| GPS Only location | β‘β‘β‘ High | Need accuracy |
| Cell Only location | β‘ Minimal | Fast/rough location |
| Last Known location | β‘ None | No new request needed |
| Photo capture | β‘β‘ Medium | As needed |
Storage:
- Photos: ~2-3 MB per photo
- Default 10 photos = ~25 MB per device
- Max 50 photos = ~125 MB per device
- Location data: Negligible (<1 MB)
Network:
- Location poll: ~1-5 KB per request
- Photo download: ~2-3 MB per photo
- Encrypted data transfer (HTTPS recommended)
CPU:
- Decryption: Minimal (async operations)
- Photo processing: Medium (EXIF extraction)
- Normal operation: Low impact
For Battery Life:
- Use "Cell Only (Fast)" when battery < 30%
- Use "GPS Only (Accurate)" when charging
- Increase normal polling interval (60+ minutes)
- Disable high frequency mode when not needed
For Accuracy:
- Location Source: "GPS Only (Accurate)"
- Allow Inaccurate Locations: OFF
- High Frequency Mode: ON (when tracking actively)
For Storage:
- Set Max Photos to 5-10 (not 50)
- Manually delete old photos periodically
- Consider automation to clean media folder
The integration provides complete photo management functionality:
-
Capture a Photo:
- Press "Capture Front Camera" or "Capture Rear Camera" button
- Wait 15-30 seconds for device to capture and upload to server
-
Download Photos:
- Set "Max Photos to Download" to desired number (default: 10)
- Press "Download Photos" button
- Photos are fetched, decrypted, and saved to
/config/media/fmd/<device-id>/or/media/fmd/<device-id>/
-
View Photos:
- Navigate to Media β FMD in Home Assistant
- Click on your device folder (e.g.,
test-user) - Browse photos in grid view
- Click to view full size
- Use photos in automations or notifications
Photo Storage:
- Location:
/media/fmd/<device-id>/(Docker/Core/K8s) or/config/media/fmd/<device-id>/(HAOS) - Format:
photo_YYYYMMDD_HHMMSS_<hash>.jpg(timestamp from EXIF data + content hash)- Example:
photo_20251019_150034_705a8c9f.jpg - Timestamp extracted from EXIF
DateTimeOriginaltag (when photo was captured) - Falls back to
photo_<hash>.jpgif EXIF data is missing
- Example:
- Size: ~2-3 MB per photo
- Organization: Each device has its own subdirectory
- Chronological sorting: Photos appear in capture order thanks to timestamp prefix
- Duplicate prevention: Content hash suffix prevents re-downloading identical photos
- No automatic polling - photos are downloaded only when requested
The integration provides remote control commands for your FMD device:
Configure which location provider is used by the Location Update button AND High Frequency Mode:
- All Providers (Default): Uses GPS, network, and fused location for best reliability
- GPS Only (Accurate): Most accurate but slower, requires clear sky view, uses more battery
- Cell Only (Fast): Fast but less accurate, uses cellular tower triangulation
- Last Known (No Request): Returns cached location without new GPS request (instant, no battery use)
Use the Location Source select entity to change the provider. The setting persists and affects:
- Manual Updates: When pressing the "Location Update" button.
- High Frequency Mode: When active tracking is enabled, each poll uses this source.
Note: Normal polling mode (passive) is unaffected by this setting as it only fetches existing data from the server.
Example automation for enabling battery-conscious location tracking:
automation:
- alias: "FMD: Use GPS when charging, Cell when on battery"
trigger:
- platform: state
entity_id: binary_sensor.my_phone_is_charging
action:
- service: select.select_option
target:
entity_id: select.fmd_test_user_location_source
data:
option: >
{% if trigger.to_state.state == 'on' %}
GPS Only (Accurate)
{% else %}
Cell Only (Fast)
{% endif %}
- service: switch.turn_on
target:
entity_id: switch.fmd_test_user_high_frequency_modeUse the Bluetooth command select entity to enable or disable Bluetooth:
- Select "Enable Bluetooth" to turn on Bluetooth
- Select "Disable Bluetooth" to turn off Bluetooth
- Requires Android 12+ BLUETOOTH_CONNECT permission
- Entity resets to "Send Command..." after sending
Use the DND command select entity to control Do Not Disturb mode:
- Select "Enable Do Not Disturb" to enable DND
- Select "Disable Do Not Disturb" to disable DND
- Requires Do Not Disturb Access permission
- Useful for bedtime automations or meeting mode
Use the Ringer Mode command select entity to change device ringer:
- Select "Normal (Sound + Vibrate)" for full sound
- Select "Vibrate Only" for vibrate-only mode
- Select "Silent" for silent mode (also enables DND)
- Requires Do Not Disturb Access permission
To protect against accidental wipes, this feature requires a two-step process:
-
Enable Safety Switch:
- Turn on the "Wipe:
β οΈ Safety switchβ οΈ " - This allows the wipe button to function
- β° Automatically disables after 60 seconds
- Turn on the "Wipe:
-
Press Wipe Button:
- While safety switch is enabled, press "Wipe:
β οΈ Executeβ οΈ " button - Device will be factory reset (all data erased)
- Safety switch automatically disables after use
- While safety switch is enabled, press "Wipe:
Use Cases:
- Device is lost/stolen and you want to protect your data
- Device needs to be decommissioned or sold
- Final resort for security/privacy protection
Important Notes:
- This command CANNOT BE UNDONE
- All data: apps, files, photos, accounts (EVERYTHING!) will be deleted
- Device will return to factory settings
- You'll need physical access to set up the device again
Note: Bluetooth, DND, and Ringer commands are fire-and-forget. Home Assistant doesn't track the actual device state, so the select entities always show "Send Command..." as a placeholder.
Notify when device arrives home:
automation:
- alias: "FMD: Notify device arrived home"
trigger:
- platform: zone
entity_id: device_tracker.fmd_my_phone
zone: zone.home
event: enter
action:
- service: notify.mobile_app
data:
title: "Device Tracking"
message: "My phone arrived home"Track device leaving work:
automation:
- alias: "FMD: Start tracking when leaving work"
trigger:
- platform: zone
entity_id: device_tracker.fmd_my_phone
zone: zone.work
event: leave
action:
- service: switch.turn_on
target:
entity_id: switch.fmd_my_phone_high_frequency_mode
- delay:
minutes: 30
- service: switch.turn_off
target:
entity_id: switch.fmd_my_phone_high_frequency_modeBedtime routine - Enable DND:
automation:
- alias: "FMD: Bedtime DND"
trigger:
- platform: time
at: "22:00:00"
action:
- service: select.select_option
target:
entity_id: select.fmd_my_phone_do_not_disturb_command
data:
option: "Enable Do Not Disturb"Morning routine - Disable DND:
automation:
- alias: "FMD: Morning wake up"
trigger:
- platform: time
at: "07:00:00"
condition:
- condition: state
entity_id: binary_sensor.workday_sensor
state: "on"
action:
- service: select.select_option
target:
entity_id: select.fmd_my_phone_do_not_disturb_command
data:
option: "Disable Do Not Disturb"Silent mode during meetings:
automation:
- alias: "FMD: Silent during calendar events"
trigger:
- platform: state
entity_id: calendar.work_calendar
to: "on"
action:
- service: select.select_option
target:
entity_id: select.fmd_my_phone_ringer_mode_command
data:
option: "Silent"Ring when device battery is low and not home:
automation:
- alias: "FMD: Low battery not home alert"
trigger:
- platform: numeric_state
entity_id: device_tracker.fmd_my_phone
attribute: battery_level
below: 15
condition:
- condition: not
conditions:
- condition: zone
entity_id: device_tracker.fmd_my_phone
zone: zone.home
action:
- service: notify.mobile_app
data:
title: "Low Battery Warning"
message: "Phone battery at {{ states.device_tracker.fmd_my_phone.attributes.battery_level }}% and not home!"
- service: button.press
target:
entity_id: button.fmd_my_phone_location_updateAuto-capture photo when device enters geofence:
automation:
- alias: "FMD: Capture photo on suspicious movement"
trigger:
- platform: zone
entity_id: device_tracker.fmd_my_phone
zone: zone.suspicious_area
event: enter
action:
- service: button.press
target:
entity_id: button.fmd_my_phone_capture_rear
- delay:
seconds: 30
- service: button.press
target:
entity_id: button.fmd_my_phone_download_photos
- service: notify.mobile_app
data:
title: "Security Alert"
message: "Device entered restricted zone - photo captured"Auto-capture photo when someone interacts with it (prior to unlock)
automation:
- alias: "FMD: Capture photo on device interaction (uses optional sensor from Home Assistant App)"
trigger:
- trigger: state
entity_id: binary_sensor.mydevice_interactive
from: "off"
to: "on"
action:
- service: button.press
target:
entity_id: button.fmd_my_phone_capture_rearAdaptive location precision based on motion:
automation:
- alias: "FMD: Adaptive location precision"
trigger:
- platform: state
entity_id: device_tracker.fmd_my_phone
attribute: speed
action:
- choose:
# Moving fast (vehicle) - use GPS only
- conditions:
- condition: template
value_template: "{{ state_attr('device_tracker.fmd_my_phone', 'speed') | float(0) > 5 }}"
sequence:
- service: select.select_option
target:
entity_id: select.fmd_my_phone_location_source
data:
option: "GPS Only (Accurate)"
# Stationary - use last known (save battery)
- conditions:
- condition: template
value_template: "{{ state_attr('device_tracker.fmd_my_phone', 'speed') | float(0) == 0 }}"
sequence:
- service: select.select_option
target:
entity_id: select.fmd_my_phone_location_source
data:
option: "Last Known (No Request)"
# Default - use all providers
default:
- service: select.select_option
target:
entity_id: select.fmd_my_phone_location_source
data:
option: "All Providers (Default)"Daily photo capture and download:
automation:
- alias: "FMD: Daily surveillance photo"
trigger:
- platform: time
at: "12:00:00"
action:
- service: button.press
target:
entity_id: button.fmd_my_phone_capture_front
- delay:
seconds: 30
- service: button.press
target:
entity_id: button.fmd_my_phone_download_photosNotify when new photos downloaded:
automation:
- alias: "FMD: Photo download notification"
trigger:
- platform: state
entity_id: sensor.fmd_my_phone_photo_count
condition:
- condition: template
value_template: "{{ trigger.to_state.state | int(0) > trigger.from_state.state | int(0) }}"
action:
- service: notify.mobile_app
data:
title: "FMD Photos"
message: "Downloaded {{ trigger.to_state.state }} new photo(s) from device"π Enhanced Security with Authentication Artifacts
Starting with fmd_api 2.0.4, this integration uses password-free authentication for improved security:
- No raw password storage: Your FMD password is never stored in Home Assistant
- Secure artifacts: Uses authentication tokens, private keys, and password hash instead
- Automatic migration: Existing installations automatically upgrade to secure storage
- Seamless reauth: Client automatically refreshes tokens without re-entering password
- Future-proof: Designed for long-term secure authentication
How It Works:
- During initial setup, you enter your FMD password once
- Integration authenticates and immediately exports secure artifacts
- Password is discarded - only artifacts are stored
- On startup, integration uses artifacts to reconnect (no password needed)
- If credentials expire, reauth flow generates new artifacts
Migration for Existing Users:
- Automatic on next restart after upgrade
- No action required - seamless transition
- Old password-based entries converted to artifacts
- Reauth flow also uses new artifact-based system
π Secure Your FMD Server
- Use HTTPS (not HTTP) for your FMD server URL
- Use strong, unique passwords (20+ characters recommended)
- Run FMD server on a private network or VPN
- Keep FMD server software updated
- Use firewall rules to restrict access
π Home Assistant Security
- Enable authentication on Home Assistant
- Use strong passwords or API tokens
- Consider network isolation for device tracking
- Regularly review Home Assistant logs
- Keep Home Assistant updated
π± Android App Permissions
The FMD Android app requires these permissions:
- β Location (always) - For tracking
- β Camera - For photo capture
- β Device Admin - For lock/wipe commands
β οΈ Bluetooth (Android 12+) - For Bluetooth controlβ οΈ Do Not Disturb Access - For DND/ringer commands
Grant permissions cautiously - only enable what you need.
π¨ Device Wipe Protection
The integration includes multiple safety layers:
- Wipe PIN required - Must set alphanumeric PIN (no spaces) before wipe works
- Safety switch required - Must enable before wipe button activates
- 60-second timeout - Safety auto-disables after 1 minute
- PIN validation - Ensures proper format before sending command
- Extensive logging - CRITICAL warnings in logs
- Auto-disable after use - Prevents repeated presses
- Cannot be undone - Final warning in documentation
PIN Requirements (fmd_api 2.0.4+):
- Must be alphanumeric (letters and numbers only)
- Cannot contain spaces or special characters
- Must be ASCII characters only
- Recommended: 8+ characters (future-proofing)
- Set via "Wipe: PIN" text entity before attempting wipe
- Location data is encrypted in transit (RSA + AES-GCM)
- Photos are encrypted on FMD server
- Data is decrypted only on Home Assistant
- Photos stored locally on Home Assistant
- Review Home Assistant's
media/fmd/permissions - Consider who has access to your Home Assistant instance
π‘ Recommendations
- Use this integration only on devices you own
- Inform device users they are being tracked
- Comply with local laws regarding tracking/surveillance
- Use device wipe only as last resort
- Test features in safe environment first
- Keep backups of important device data
This integration includes comprehensive test coverage for Home Assistant Core submission requirements.
Install test dependencies:
pip install -r requirements_test.txtRun all tests:
pytestRun tests with coverage:
pytest --cov=custom_components.fmd --cov-report=html --cov-report=term-missingView coverage report:
# Open htmlcov/index.html in your browserThe test suite includes:
- Unit tests - All platform entities (device_tracker, button, switch, select, number, sensor)
- Integration tests - Setup, unload, and error handling
- Config flow tests - User configuration, validation, and error scenarios
- Fixtures - Mock FMD API with realistic responses
Test files:
tests/conftest.py- Shared fixtures and test helperstests/test_init.py- Integration lifecycle teststests/test_config_flow.py- Configuration flow teststests/test_device_tracker.py- Device tracker entity teststests/test_button.py- Button entity tests (7 buttons)tests/test_switch.py- Switch entity tests (4 switches)tests/test_select.py- Select entity tests (4 selects)tests/test_number.py- Number entity tests (3 numbers)tests/test_sensor.py- Sensor entity tests (photo count)
Tests run automatically on every push and pull request via GitHub Actions:
- Python 3.11 and 3.12
- Coverage reporting to Codecov
- Automated test result checks
To be included in Home Assistant Core, the following items must be completed:
Code Quality & Standards:
- Code review - Pass Home Assistant core team code review
- Type hints - β Add complete type hints to all functions and methods
- Async best practices - Ensure all I/O operations are properly async
- Error handling - Comprehensive error handling and user-friendly error messages
- Code coverage - β Achieve minimum 90% test coverage
Testing:
- Unit tests - β Write comprehensive unit tests for all components
- Integration tests - β Test config flow, entities, and device tracker
- Mock FMD server - β Create test fixtures for API responses
- Test coverage reports - β Set up pytest-cov and coverage reporting
Documentation:
- Component documentation - Create Home Assistant documentation page
- Translation strings - Add translation support for all UI strings
- Configuration examples - Provide YAML examples (if applicable)
- Architecture documentation - Document component architecture and design decisions
Dependencies:
- FMD client library - Published as
fmd_apiPyPI package- β Published at: https://pypi.org/project/fmd-api/
- β Follows semantic versioning (v0.1.0)
- β Separate repository with documentation
- Dependency review - All dependencies must be approved by HA core team
Quality Assurance:
- Pylint/Flake8 - Pass all linting checks with HA configuration
- MyPy - Pass static type checking
- hassfest - Pass Home Assistant validation tool
- Quality scale - Achieve Bronze quality scale minimum (Silver preferred)
Additional Requirements:
- Branding - β
Merged to Home Assistant brands repository
- Official FMD icon now available globally
- Path:
custom_integrations/fmd/
- IoT class - Verify "cloud_polling" classification is appropriate
- Breaking changes - Document any breaking changes for migration
- Performance - Ensure efficient polling and minimal resource usage
Medium Priority:
-
Device stats - Display network information
- IP address, WiFi SSID, WiFi BSSID
- Requires FMD "stats" command parsing
- Priority: Medium
-
GPS status - Display GPS and battery status
- GPS state (on/off), battery level
- Requires FMD "gps" command parsing
- Priority: Medium
Low Priority:
- Account deletion - FMD account management
- Requires FMD server API addition
- Low priority (can do manually on server)
- Check that your FMD server is accessible from Home Assistant
- Verify your credentials are correct in the integration configuration
- Check Home Assistant logs for errors (
custom_components.fmd) - Ensure your device is sending location updates to the FMD server
- Verify all required dependencies are installed (aiohttp, argon2-cffi, cryptography)
- Check for errors in Home Assistant logs during startup
- Try removing and re-adding the integration
Location Updates:
- β±οΈ Location polling is not real-time (minimum 1-minute interval)
- π Requires device to have internet connectivity
- π‘ GPS accuracy depends on device location (outdoors vs. indoors)
- β‘ High frequency mode drains device battery faster
Commands:
- π¬ Commands are fire-and-forget (no confirmation from device)
- π Device must be online to receive commands
- β° Command execution depends on device connectivity
- π« No state feedback (can't query if Bluetooth is on/off)
Photos:
- πΈ Photo capture takes 15-30 seconds
- πΎ Photos remain on FMD server until manually deleted
- π No automatic photo cleanup (must delete manually)
- πΌοΈ EXIF timestamps may be missing from some photos
Permissions:
β οΈ Bluetooth control requires Android 12+ BLUETOOTH_CONNECT permissionβ οΈ DND/Ringer control requires Do Not Disturb Access permissionβ οΈ Some features may not work on all Android versions
Device Wipe:
- π¨ Cannot be undone once device receives command
- β±οΈ Execution time depends on device (immediate to minutes)
- π± Requires device to be online to receive command
- π Device must have Device Admin permission granted to FMD app
Maintenance release focusing on dependency updates and compatibility testing.
Changes:
- π¦ Dependency: Bumped
fmd-apito2.0.7. - β
Verified compatibility of the integration and full test suite with
fmd-api==2.0.7.
Release focused on fixing polling interval persistence and improving code quality.
Changes:
- π Fix: Configured polling intervals now correctly persist across restarts (previously reverted to defaults).
- π§Ή Strict Typing: Comprehensive type hinting added to
device_tracker.pyfor better code stability. - π‘οΈ Robust Configuration: Enhanced type safety when reading configuration values during startup.
Maintenance release to update dependencies and improve polling reliability.
Changes:
- π― Smarter High Frequency Tracking: High Frequency Mode now respects your "Location Source" selection (e.g., Cell Only, GPS Only) instead of always forcing "All Providers".
- π¦ Updated dependency to
fmd-api==2.0.5 - π‘οΈ Polling reliability: Added protection against overlapping updates to prevent task pile-ups and ensure schedule adherence.
- π Improved polling logic: Ensures polling tasks are managed correctly, preventing stalls if the server or device is slow to respond.
Note: This release included efforts to address polling interval persistence; however, some restart-edge cases remained and were fully resolved in v1.1.3.
Short maintenance release focused on restoring button functionality introduced with the fmd_api 2.0.4 upgrade.
Changes:
- Fix: Button entities (Lock device, Photo: Download, Wipe: Execute) now work reliably by constructing
Device(client, device_id)instead of calling a non-existentclient.device()method. This also restores lock functionality, including support for custom lock-screen messages. - Tests/Docs: Updated Device class mocking in tests and added Windows test setup guide at
docs/TESTS_WINDOWS.md.
π Security & Feature Update
This version adopts all improvements from fmd_api 2.0.4, with focus on security and safety features.
Highlights:
- π Password-free authentication - Credentials stored as secure artifacts (no raw passwords)
- πΈ Modern picture API - Updated to use
get_picture_blobs()anddecode_picture() - π Wipe PIN validation - Added required PIN entity for device wipe safety
- π¬ Lock message support - Optional message parameter for lock screen display
- π‘οΈ Enhanced error handling - Specific exception types with clear user messages
- π¦ Updated dependency to
fmd-api==2.0.4
New Entities:
text.fmd_{device}_wipe_pin- Required alphanumeric PIN for device wipe (password-mode)text.fmd_{device}_lock_message- Optional message to display on lock screen
Security Improvements:
- No raw password storage: Automatic migration to secure authentication artifacts
- PIN validation: Wipe command requires validated alphanumeric PIN (no spaces)
- Better errors: FmdAuthError, FmdConnectionError, FmdError with actionable messages
API Changes:
- Deprecated picture methods replaced with modern alternatives
- Lock command now supports optional message parameter (client sanitizes automatically)
- Wipe command requires PIN and always passes confirm=True flag
Migration:
- Automatic - Existing installations migrate to password-free auth on startup
- Seamless - No user action required for authentication upgrade
- Required - Must set wipe PIN before device wipe button will work
- Optional - Lock message is optional (lock works without it)
Upgrade Notes:
- Update via HACS (or pull latest release) and restart Home Assistant
- Authentication automatically migrates to secure artifacts (password removed)
- Action required: Set "Wipe: PIN" text entity before attempting device wipe
- Optional: Set "Lock: Message" text entity for lock screen messages
Breaking Changes:
- Device wipe now requires PIN to be set (safety improvement)
- Internal picture API methods replaced (user-facing behavior unchanged)
π First Stable Release
This version marks the transition from beta to a stable, production-ready integration.
Highlights:
- π¦ Updated core dependency to
fmd-api==2.0.3(performance & robustness improvements) - β Declared stable: no known critical issues after extended beta test of 0.9.x line
- π§ͺ Maintains high test coverage (β₯96%) across all entity platforms
- π Improved photo/media handling reliability in varied Home Assistant environments
- π Refined internal executor usage for non-blocking decrypt and file operations
Upgrade Notes:
- Update via HACS (or pull latest release) and restart Home Assistant.
- No reconfiguration required; existing config entries migrate seamlessly.
- If you were on a pre-0.9.0 version, review the 0.9.x notes below for feature additions.
Post-Upgrade Validation Checklist (optional):
- Confirm device tracker updates within your configured interval.
- Press Location Update button and verify fresh attributes (provider, timestamp).
- (Optional) Capture and Download a photo to confirm media folder access.
Looking Ahead:
- Focus will shift to stablity and minor improvements to work towards inclusion in Home Assistant Core.
Thanks to all testers who helped harden the 0.9.x series.
π MAJOR REWRITE: fmd-api v2.0.1 Migration (Beta)
This was the final beta milestone preceding the stable 1.0.0 release and represented the most significant architectural overhaul since project inception.
Breaking Changes:
- π§ Complete API rewrite - Migrated from
fmd-api v1.xtofmd-api v2.0.1- All FMD server communication now uses the new
FmdClientclass - Improved async/await patterns throughout
- Enhanced error handling and connection management
- All FMD server communication now uses the new
- π¦ Updated dependencies - Now requires
fmd-api==2.0.1 - π Config flow improvements - Added reauthentication flow support
- βοΈ State persistence - All configuration entities (numbers, switches, selects) now properly restore state across restarts
- π§ͺ Test infrastructure overhaul - Full test suite rewritten for new API patterns
New Features:
- β Reauthentication flow - Update credentials without removing/re-adding integration
- β Persistent settings - Entity configurations survive Home Assistant restarts
- β Improved location updates - High-frequency mode now more reliable with better request handling
- β Better error handling - ConfigEntryNotReady for graceful service outage handling
Under the Hood:
- ποΈ Modern API patterns -
FmdClient.create()factory method for async initialization - π Enhanced security - Improved encryption and decryption handling via executor
- π Type safety - Comprehensive type hints with TYPE_CHECKING guards
- π§ͺ Test coverage - Maintained ~94% coverage with all 193 tests passing
- π§ CI/CD improvements - Resolved dependency conflicts (josepy/acme, aiohttp)
- π Code quality - Removed migration comments, unified type hints, strict imports
Migration Guide:
- Backup your configuration (Settings β System β Backups)
- Update the integration via HACS
- Restart Home Assistant
- Verify all entities are working correctly
- If you experience authentication errors, use the new reauthentication flow:
- Go to Settings β Devices & Services β FMD
- Click the three dots β Reconfigure
- Enter your credentials again
Known Issues:
- None currently - please report any issues on GitHub!
Transition: Community testing of this version informed the stability designation in v1.0.0.
Technical Details:
- All code strictly imports
FmdClient(no fallback imports) - Tests updated to mock
FmdClientinstead of legacyFmdApi - Photo downloads use executor for decryption (non-blocking)
- Location polling respects configured intervals and sources
- Total entities: 20 per device
Credits:
- Huge thanks to the FMD-FOSS team for the excellent FMD ecosystem
- Special thanks to beta testers and contributors
Test entity state restore
- β Extended solution for entity state to all that store values needing restored!
- Total entities: 20 per device
Test entity state restore
- β Tested solution for entity state restore on restart/reload (Issue #1)
- Total entities: 20 per device
Translations and code coverage
- β Added translation files for several languages
- β Improved code testing coverage
- β Initial work on reauthentication flow
- Total entities: 20 per device
Graceful Error Handling & Linting
- β Added ConfigEntryNotReady exception for graceful handling of temporary service outages
- β Fixed pre-commit pipeline with dynamic Python version support
- β Resolved all linting issues (unused imports, line length violations)
- β Improved code quality and compliance
- Total entities: 20 per device
Major Refactor: PyPI Package Migration
- β
Migrated from embedded
fmd_clientto PyPI packagefmd-api - β Simplified dependencies and improved maintainability
- β Separate versioning for API client library
- β
Photo storage management improvements
- Changed photo count sensor to show total stored photos
- Added
last_download_countattribute - Renamed "Max photos to download" β "Photo: Max to retain"
- Added "Photo: Auto-cleanup" switch (default OFF)
- Automatic deletion of oldest photos when limit exceeded
- β Fixed entity icons for location update and high-frequency interval
- β
Official branding merged to Home Assistant brands repository
- Integration now displays official FMD icon globally
- Available at:
custom_integrations/fmd/
- Total entities: 20 per device
Icon Improvements
- β Submitted integration branding to Home Assistant brands repository
- β Improved entity icon definitions
- Total entities: 20 per device
Unit Conversion Feature
- β Added imperial units configuration option
- β Converts speed (m/s β mph), altitude (m β ft), and GPS accuracy (m β ft)
- β Added unit indicators in device tracker attributes
- β Configurable during initial setup
- Total entities: 20 per device
UX Improvements: Entity Naming & Organization
- β Improved entity naming for better organization
- β Photo entities grouped with "Photo:" prefix
- β
Wipe entities clearly marked with
β οΈ warning symbol - β Simplified select entity names
- Total entities: 19 per device
Phase 4: Device Wipe with Safety Mechanism
- β Added Device Wipe button (factory reset)
- β Added Device Wipe Safety switch (60-second timeout)
- β Enhanced logging for wipe operations
- β Two-step safety process to prevent accidents
- β MIT License added
- β Comprehensive FMD team attribution
- Total entities: 19 per device
Phase 2: Configurable Location Source
- β Added Location Source select entity
- β Four location modes: All/GPS/Cell/Last Known
- β Battery-conscious tracking support
- Total entities: 17 per device
Phase 1: Device Control Commands
- β Added Bluetooth, DND, and Ringer Mode control
- β Select entity placeholder pattern
- Total entities: 16 per device
Photo Capture & Download
- β Front & rear camera capture
- β Photo download with encryption
- β Media browser integration
- β EXIF timestamp extraction
Q: Do I need to run my own FMD server? A: Hosting your own is preferred but this integration can be used with a publicly hosted FMD server, like the one hosted by Nulide. To host your own please see FMD Server setup.
Q: Does this work without the FMD Android app? A: No, you must install the FMD Android app on the device you want to track. The app communicates with the FMD server though, not directly with the android app!
Q: Can I track multiple devices? A: Yes! Add a new integration instance for each device. Each device gets its own set of entities.
Q: Why is my location not updating? A: Check: 1) Device has internet, 2) FMD app is running, 3) Location permissions granted, 4) Device is sending data to server (check FMD server logs). If you aren't seeing location data with this integration, first login to the FMD server directly to see if the data has actually been sent there.
Q: How do I know if a command was received? A: Commands are fire-and-forget. Check device physically or use another method to confirm. There's no acknowledgment from the device.
Q: Can I see Bluetooth/DND state in Home Assistant? A: No, FMD doesn't support querying device state. Commands are one-way only. You can, however, configure the official Home Assistant App to enable sensors so it collects this information.
Q: How much battery will this use on my android device? A: Normal mode: None, since it just polls the FMD server. High-frequency mode: Can use significant battery depending on the location update type that is configured. This will actively wake up the device every X minutes to request new or cached location information. See Performance.
Q: Where are photos stored?
A: /media/fmd/<device-id>/ (Docker/Core) or /config/media/fmd/<device-id>/ (HAOS). Photos appear in Media Browser automatically.
They will not populate here automatically. You'll need to click the Download button entity first. If photos exist for that user, you'll see the photo_count entity reflect the number of saved photos.
Q: Can I download photos older than the configured max? A: No, increase "Max Photos to Download" setting before pressing "Download Photos" to get more history. If your photo_max_to_retain entity is configured with a value of 10 and you have 12 photos in your FMD account then the oldest 2 will be deleted when you click the Download button in Home Assistant. This will only delete the copies in Home Assistant. No changes will be made to your FMD account or the data stored there.
Q: Is my data encrypted? A: It is encrypted on the FMD server but is not encrypted in Home Assistant. Any users with access to Home Assistant will essentially have access to all of the features of FMD, including your photos and the ability to factory reset your device. Use with caution!
Q: What happens if I accidentally press the wipe button? A: Nothing! The safety switch must be enabled first. The wipe button is blocked by default. If the safety switch is turned On and the Wipe/Execute button is pressed, a timer will begin that will factory reset your device in 60 seconds.
Q: Can I undo a device wipe? A: No, device wipe is permanent. All data is erased. This is an FMD feature, not controllable by this integration.
Q: Does this work on iOS/iPhone? A: No, FMD is Android-only. This integration only works with Android devices running the FMD app.
Q: Can I use this for fleet/business tracking? A: Yes, the MIT License allows commercial use. Add one integration instance per device.
This integration would not exist without the excellent work of the FMD-FOSS team:
- FMD Project: https://fmd-foss.org
- Created by: Nulide (Founder)
- Maintained by: Thore and the FMD-FOSS team
- FMD Android App: https://gitlab.com/fmd-foss/fmd-android
- FMD Server: https://gitlab.com/fmd-foss/fmd-server
- FMD Home Assistant Integration: https://github.com/devinslick/home-assistant-fmd
Thank you to Nulide, Thore, and all FMD contributors for creating this privacy-respecting, open source device tracking solution!
This integration is a third-party client that communicates with FMD servers. It is not affiliated with or endorsed by the FMD-FOSS project. For full attribution details, see CREDITS.md.
If you find this integration useful, please support the FMD project:
- β Star the FMD repositories on GitLab
- π Contribute to the FMD project
- π’ Spread the word about FMD
Contributions to this Home Assistant integration are welcome! If you have any ideas, suggestions, or bug reports, please open an issue or submit a pull request.
This integration uses:
- Async/await for all I/O operations
- aiohttp for HTTP communication
- RSA-3072 encryption for key exchange
- AES-GCM for data encryption
- Argon2id for password hashing
This project is licensed under the MIT License - see the LICENSE file for details.
This integration is completely free and open source. You are free to use, modify, and distribute it according to the terms of the MIT License.
- β Free to use for personal or commercial purposes
- β Free to modify and create derivative works
- β Free to distribute original or modified versions
- β No warranty - provided "as is"
- β Attribution appreciated but not legally required