Go to file
2025-10-29 17:01:47 +00:00
data moved the example file to docs director 2025-10-29 17:01:47 +00:00
docs Organize: Move refactoring helper files to docs/ 2025-10-29 16:51:17 +00:00
tests moving items around 2025-10-28 00:21:08 +00:00
.gitignore Refactor: Split TasmotaManager into modular structure 2025-10-29 16:38:03 +00:00
configuration.py Refactor: Split TasmotaManager into modular structure 2025-10-29 16:38:03 +00:00
console_settings.py Refactor: Split TasmotaManager into modular structure 2025-10-29 16:38:03 +00:00
discovery.py Refactor: Split TasmotaManager into modular structure 2025-10-29 16:38:03 +00:00
network_configuration.json Fix Issue #5: Remove empty string from Traditional console_set 2025-10-28 09:47:01 +00:00
pyproject.toml Rename main.py to TasmotaManager.py 2025-10-29 16:42:50 +00:00
README.md Save latest session changes: migrate to console_set profiles, device_list structure with per-device console_set, docs updated, formatting updates 2025-08-28 08:07:29 -05:00
reporting.py Refactor: Split TasmotaManager into modular structure 2025-10-29 16:38:03 +00:00
TasmotaManager.py Rename main.py to TasmotaManager.py 2025-10-29 16:42:50 +00:00
unifi_client.py Refactor: Split TasmotaManager into modular structure 2025-10-29 16:38:03 +00:00
unknown_devices.py Refactor: Split TasmotaManager into modular structure 2025-10-29 16:38:03 +00:00
utils.py Refactor: Split TasmotaManager into modular structure 2025-10-29 16:38:03 +00:00

TasmotaManager

A Python utility for discovering, monitoring, and managing Tasmota devices on a network using UniFi Controller.

Features

  • Discovers Tasmota devices on the network via UniFi Controller API
  • Track device changes over time (new, moved, deprecated devices)
  • Checks and updates MQTT settings on Tasmota devices
  • Generates detailed device information including firmware versions
  • Processes unknown devices (matching unknown_device_patterns) to set up names and MQTT

Requirements

  • Python 3.6+
  • UniFi Controller with API access
  • Network with Tasmota devices

Dependencies

  • requests
  • urllib3
  • Standard library modules (json, logging, os, sys, datetime, re, time, argparse)

Installation

  1. Clone this repository
  2. Install required packages:
    pip install requests urllib3
    
  3. Create a configuration file (see below)

Configuration

Create a network_configuration.json file with the following structure:

{
  "unifi": {
    "host": "https://your-unifi-controller.local",
    "username": "your-username",
    "password": "your-password",
    "site": "default",
    "network_filter": {
      "network_name": {
        "name": "Human-readable name",
        "subnet": "192.168.1",
        "exclude_patterns": [
          "device-to-exclude*"
        ],
        "unknown_device_patterns": [
          "tasmota*",
          "ESP-*"
        ]
      }
    }
  },
  "mqtt": {
    "Host": "mqtt-broker.local",
    "Port": 1883,
    "User": "mqtt-user",
    "Password": "mqtt-password",
    "Topic": "%hostname_base%",
    "FullTopic": "%prefix%/%topic%/",
    "NoRetain": false
  },
  "device_list": {
    "Example_Device_Template": {"template": "{\"NAME\":\"Example\",\"GPIO\":[0],\"FLAG\":0,\"BASE\":18}", "console_set": "Default"}
  },
  "console_set": {
    "Default": [
      "SwitchRetain Off",
      "ButtonRetain Off",
      "PowerOnState 3",
      "PowerRetain On",
      "SetOption1 0",
      "SetOption3 1",
      "SetOption4 1",
      "SetOption13 0",
      "SetOption19 0",
      "SetOption32 8",
      "SetOption53 1",
      "SetOption73 1",
      "rule1 on button1#state=10 do power0 toggle endon"
    ],
    "alt": [
      "SwitchRetain Off",
      "ButtonRetain Off",
      "PowerOnState 3",
      "PowerRetain On",
      "SetOption1 0",
      "SetOption3 1",
      "SetOption4 1",
      "SetOption13 0",
      "SetOption19 0",
      "SetOption32 8",
      "SetOption53 1",
      "SetOption73 1",
      "rule1 on button1#state=10 do power0 toggle endon"
    ]
  }
}

About device_list and console_set profiles:

  • device_list: map each device key to an object with:
    • template: the Tasmota template JSON string to apply when matching that device name
    • console_set: the name of the console_set profile to apply (e.g., "Default" or "alt")
  • console_set: a dictionary of named command lists. Define as many profiles as needed and select them per device via device_list.

Note:

  • In the mqtt section, the Topic supports the placeholder "%hostname_base%". The script will replace this with the base of the device's hostname (everything before the first dash). For example, for a device named "KitchenLamp-1234", the Topic will be set to "KitchenLamp".
  • NoRetain controls Tasmota's SetOption62 (true = No Retain, false = Use Retain).
  • FullTopic typically remains "%prefix%/%topic%/" and is applied according to Tasmota's command format.

Usage

Basic usage:

python TasmotaManager.py

With options:

python TasmotaManager.py --config custom_config.json --debug --skip-unifi

Hostname report mode:

python TasmotaManager.py --unifi-hostname-report
# Saves JSON to TasmotaHostnameReport.json and prints a summary

Command-line options:

  • --config: Path to configuration file (default: network_configuration.json)
  • --debug: Enable debug logging
  • --skip-unifi: Skip UniFi discovery and use existing current.json
  • --process-unknown: Process unknown devices (matching unknown_device_patterns) to set up names and MQTT
  • --unifi-hostname-report: Generate a report comparing UniFi and Tasmota device hostnames
  • --Device: Process a single device by hostname or IP address

Single Device Processing

The script can process a single device by hostname or IP address using the --Device parameter. When this parameter is provided, the script will:

  1. Connect to the UniFi controller to find the device
  2. If a hostname is provided, the script will find the corresponding IP address
  3. If an IP address is provided, the script will find the corresponding hostname
  4. Verify the device is in the correct network (as defined in network_filter)
  5. Check if the device is in the exclude_patterns list (if so, processing will be skipped)
  6. Check if the device is in the unknown_device_patterns list:
    • If it is, the script will run the unknown device procedure for just this one device
    • If not, the script will run the normal MQTT configuration procedure for just this one device
  7. Save the device details to TasmotaDevices.json

UniFi OS Hostname Tracking Issue

UniFi OS (including UDM-SE) has a known issue with keeping track of host names. If a hostname is updated and the connection reset, UniFi will not keep track of the new name. When in Device mode, when the user enters a new host name, the script updates the name, but UniFi OS may not pick up the new name.

The script includes a workaround that checks the device's self-reported hostname before declaring it unknown, which helps in most cases.

For UDM-SE specifically, if you need to force UniFi to recognize the new host names, you can restart the UDM-SE via "Settings/Control Plane/Console/Restart". When the UDM-SE comes back online, it will have the new host names. Note that this process takes several minutes to complete.

Hostname Matching Features

When using a hostname with the --Device parameter, the script supports:

  • Exact matching: The provided hostname matches exactly (case-insensitive)
  • Partial matching: The provided hostname is contained within a device's hostname
    • Example: --Device Master will match devices named "MasterLamp-5891" or "MasterBedroom"
  • Wildcard matching: The provided hostname contains wildcards (*) that match any characters
    • Example: --Device Master* will match "MasterLamp-5891" but not "BedroomMaster"
    • Example: --Device *Lamp* will match any device with "Lamp" in its name

If multiple devices match the provided hostname pattern, the script will:

  1. Log a warning showing all matching devices
  2. Automatically use the first match found
  3. Continue processing with that device

This feature is useful for:

  • Setting up or updating a single new device without processing all devices
  • Troubleshooting a specific device
  • Quickly checking if a device is properly configured
  • Working with devices when you only remember part of the hostname

Example usage:

python TasmotaManager.py --Device mydevice.local
# or
python TasmotaManager.py --Device 192.168.8.123
# Partial match example
python TasmotaManager.py --Device Master
# Wildcard match example
python TasmotaManager.py --Device *Lamp*

Unknown Device Processing

The script can process devices that match patterns in the unknown_device_patterns list (like "tasmota_" or "ESP-" prefixed devices). When using the --process-unknown flag, the script will:

  1. Identify devices matching the unknown device patterns
  2. Check if each device has a toggle button (indicating it's a light switch or power plug)
  3. Toggle the button at 1/2 Hz (on/off every two seconds) to help identify the physical device
  4. How to enter the hostname:
    • The script will display a clear prompt in the console showing the current device name and IP address
    • While the device is toggling, you'll see a prompt asking for a new name for the device
    • Type the new hostname directly in the console and press Enter
    • All debug messages are completely suppressed during this process to keep the console clear
  5. Once a hostname is entered, the script will:
    • Configure the "Friendly Name 1" field with the new hostname
    • Enable MQTT if not already enabled
    • Configure MQTT settings from the configuration file
    • Save the configuration and reboot the device
  6. Move on to the next unknown device

This feature helps automate the setup of new Tasmota devices that haven't been properly named yet.

Console Parameters

The script supports setting Tasmota console parameters via console_set (preferred). As of this version, console_set is a dictionary of named lists (e.g., "Default", "alt"). You can select which set to apply per device by specifying the console_set name in each device_list entry. A legacy console dict and the legacy list-style console_set are still accepted for backward compatibility, but may be removed in the future. After verifying and updating MQTT settings, the script will apply all console parameters to each device. This allows you to:

  • Configure device behavior (PowerOnState, SetOptions, etc.)
  • Set up rules for button actions
  • Configure retain flags for various message types
  • Apply any other Tasmota console commands

Command Retry Logic and Error Handling

When setting console commands, the script implements robust error handling with automatic retry logic:

  • If a command times out or fails, the script will automatically retry up to 3 times
  • Between retry attempts, the script waits for 1 second before trying again
  • After 3 failed attempts, the command is marked as failed and the script continues with other commands
  • All command failures are tracked and a summary is displayed at the end of execution
  • The failure summary is grouped by device and shows which commands failed and the specific errors

This retry mechanism helps handle temporary network issues or device busy states, making the script more reliable in real-world environments with potentially unstable connections.

Retain Parameters Behavior

For all Retain parameters (ButtonRetain, SwitchRetain, PowerRetain), the script automatically sets the opposite state first before applying the final state specified in the configuration. This is necessary because the changes (not the final state) are what create the update of the Retain state at the MQTT server.

For example, if you specify "PowerRetain": "On" in your configuration:

  1. The script will first set PowerRetain Off
  2. Then set PowerRetain On

This ensures that the MQTT broker's retain settings are properly updated. The values in the configuration represent the final desired state of each Retain parameter.

Automatic Rule Enabling

The script automatically enables rules when they are defined. If you include a rule definition (e.g., rule1, rule2, rule3) in the console section, the script will automatically send the corresponding enable command (Rule1 1, Rule2 1, Rule3 1) to the device. This means you no longer need to include both the rule definition and the enable command in your configuration.

For example, this configuration:

{
  "console": {
    "rule1": "on button1#state=10 do power0 toggle endon"
  }
}

Will automatically enable rule1 on the device, equivalent to manually sending both:

rule1 on button1#state=10 do power0 toggle endon
Rule1 1

Each parameter is sent as a command to the device using the Tasmota HTTP API. The device details in TasmotaDevices.json will include a console_status field indicating whether console parameters were updated.

For detailed documentation of all available SetOptions and other console commands, please refer to the CONSOLE_COMMANDS.md file. This documentation includes:

  • Explanations of all SetOptions currently used in the configuration
  • Additional useful SetOptions that can be added
  • MQTT retain settings
  • Power settings
  • Rules configuration

The documentation is based on the official Tasmota Commands Reference.

Output Files

The script generates several output files:

  • current.json: List of currently active Tasmota devices
  • deprecated.json: Devices that were previously active but are no longer present
  • TasmotaDevices.json: Detailed information about each device, including MQTT and console parameter status

License

This project is licensed under the MIT License - see the LICENSE file for details.

Publishing a Python Script on GitHub

This project already uses git. If you are asking generally “what has to happen to publish a Python script on GitHub?”, here is a concise checklist you can follow for this or any Python script.

Prerequisites:

  • A GitHub account
  • Git installed locally (git --version)

Basic steps (new project):

  1. Create/prepare your project directory
    • Include: README.md, your .py files, optional LICENSE, optional requirements.txt
  2. Initialize git and make the first commit
    • git init
    • git add .
    • git commit -m "Initial commit"
    • Optionally set the default branch to main: git branch -M main
  3. Create a new, empty repository on GitHub
    • In your browser: New repository → name it (e.g., TasmotaManager) → Create repository (do not add README if you already have one locally)
  4. Add the GitHub remote and push

If you already have a local git repo (like this one):

  • Ensure your latest work is committed: git add -A && git commit -m "Your message"
  • Optionally rename your current branch to main: git branch -M main
  • Create the GitHub repo (empty) via the web UI
  • Add remote and push:

Recommended extras:

  • .gitignore for Python (to avoid committing virtualenvs, pycache, etc.)
  • LICENSE file so others know how they can use your code (MIT, Apache-2.0, etc.)
  • requirements.txt if your script uses external packages (pip freeze > requirements.txt or hand-curate)
  • A brief Usage section in README with example commands

Optional but useful:

Thats all that has to happen to publish a Python script on GitHub: have a local git repository, connect it to a new GitHub repository (remote), and push your commits. After that, you can collaborate, open issues/PRs, and manage releases directly on GitHub.

FAQ: Do I need a setup.py to publish on GitHub?

  • No. You do not need a setup.py (or any packaging file) to publish code on GitHub. GitHub is a git hosting platform—pushing your commits is sufficient.
  • setup.py (legacy) or pyproject.toml (modern, PEP 621) is only needed if you want to package your project so it can be installed with pip (for example, from PyPI or via a git+https URL).
  • If your goal is simply to share the script and have users clone and run it, you dont need setup.py or pyproject.toml.
  • If you want users to pip install your project:
    • Prefer a modern pyproject.toml with a build backend (e.g., setuptools, hatchling, poetry).
    • Legacy projects can use setup.py/setup.cfg.
  • Reference: Packaging Python Projects (Python Packaging User Guide) https://packaging.python.org/en/latest/tutorials/packaging-projects/

What does it take to make a pyproject.toml?

To package this project so it can be installed with pip (and optionally published to PyPI), you need a pyproject.toml that:

  • Declares a build backend in [build-system] (e.g., setuptools)
  • Provides PEP 621 project metadata in [project]
  • Tells the backend what to include (for a single-module project like this, use py-modules)
  • Optionally defines a console script entry point so users can run a command after installation

A minimal, working pyproject.toml for this repository looks like this:

[build-system]
requires = [
  "setuptools>=64",
  "wheel"
]
build-backend = "setuptools.build_meta"

[project]
name = "tasmota-manager"
version = "1.00"
description = "Discover, monitor, and manage Tasmota devices via UniFi Controller."
readme = "README.md"
requires-python = ">=3.6"
license = { text = "MIT" }
authors = [
  { name = "TasmotaManager Contributors" }
]
dependencies = [
  "requests",
  "urllib3"
]

[project.scripts]
# After installation, users can run `tasmota-manager`
# which calls main() inside TasmotaManager.py
"tasmota-manager" = "TasmotaManager:main"

[tool.setuptools]
# This project is a single-module distribution (TasmotaManager.py)
py-modules = ["TasmotaManager"]

Build and install locally:

  • Install the build tool (once): pip install build
  • Build the distribution: python -m build
    • Artifacts will be placed in dist/ (a .whl and a .tar.gz)
  • Install the wheel: pip install dist/tasmota_manager-1.00-py3-none-any.whl
    • After install, run: tasmota-manager --help

Optional: publish to PyPI

  • pip install twine
  • twine upload dist/*

Thats all it takes: choose a backend, declare metadata, and include your module(s). For larger projects with packages (src layouts), you would adjust the setuptools configuration accordingly.