Skip to content
Open
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ In the `docker run` command listed above, the DB files (commands.db and blasters
Endpoint | HTTP Method | Description
-------- | ----------- | -----------
`/discoverblasters` | `GET` | Discovers all new Broadlink RM blasters and adds them to the database (Note: blasters must be in the database before they can be used by the application, and they must be on and connected to the local network to be discoverable. You can add the Broadlink devices to your network using the instructions [here](https://github.com/mjg59/python-broadlink#example-use)). Blasters will be added to the database unnamed, so it's recommended to use `PUT /blasters/<attr>/<value>?new_name=<new_name>` to set a friendly name for each blaster.<br><br>NOTE: Discovery will also update blaster IP addresses when applicable.
`/discoverblasters?at_ip=<value>` | `GET` | Discovers a Broadlink RM blaster at the specified IP address and adds it to the database. This can be used to discover and add [locked blasters](https://github.com/mjg59/python-broadlink/issues/719), or blasters that otherwise cannot be discovered.
`/blasters` | `GET` | Gets all blasters (only returns blasters that have already been discovered once). |
`/blasters?target_name=<target_name>&command_name=<command_name>` | `POST` | Sends command `<command_name>` for target `<target_name>` to all blasters.
`/blasters/<attr>/<value>` | `GET` | Gets specified blaster. `<attr>` should be either `ip`, `mac`, or `name`, and `<value>` should be the corresponding value.
Expand All @@ -84,6 +85,7 @@ Endpoint | HTTP Method | Description
2. The database files are in SQLite3 format and can be hand edited if needed. I use [SQLiteStudio](https://sqlitestudio.pl/index.rvt).
3. To reset all settings/data, simply stop the container/app, delete the two .db files, and restart.
4. This was tested on an RM3 Mini but should theoretically support any RM device that [python-broadlink](https://github.com/mjg59/python-broadlink) does.
5. Blasters must be unlocked (accessible via WLAN) to be controlled via this program, otherwise you may get `Authentication failed` errors (see [mjg59/python-broadlink#719](https://github.com/mjg59/python-broadlink/issues/719)). To unlock a blaster in the Broadlink app: select the device, tap "..." in the top tap, click "Property", then find the "Lock device" setting and turn it off.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (documentation): Fix typo: 'top tap' should be 'top right'

Suggested change
5. Blasters must be unlocked (accessible via WLAN) to be controlled via this program, otherwise you may get `Authentication failed` errors (see [mjg59/python-broadlink#719](https://github.com/mjg59/python-broadlink/issues/719)). To unlock a blaster in the Broadlink app: select the device, tap "..." in the top tap, click "Property", then find the "Lock device" setting and turn it off.
5. Blasters must be unlocked (accessible via WLAN) to be controlled via this program, otherwise you may get `Authentication failed` errors (see [mjg59/python-broadlink#719](https://github.com/mjg59/python-broadlink/issues/719)). To unlock a blaster in the Broadlink app: select the device, tap "..." in the top right, click "Property", then find the "Lock device" setting and turn it off.


## Shout outs
1. @mjg59 for [python-broadlink](https://github.com/mjg59/python-broadlink)
Expand Down
2 changes: 1 addition & 1 deletion app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def process_response(self, req, resp, resource, req_succeeded):

class DiscoverRESTResource(object):
def on_get(self, req, resp):
resp.body = json.dumps(blaster_db.get_new_blasters())
resp.body = json.dumps(blaster_db.get_new_blasters(at_ip=req.get_param("at_ip", required=False)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚨 suggestion (security): Consider adding input validation for the 'at_ip' parameter

While the 'at_ip' parameter is optional, it's important to validate it as a valid IP address when provided. This will enhance the security and reliability of the API.

from ipaddress import ip_address

def validate_ip(ip):
    try:
        ip_address(ip)
        return True
    except ValueError:
        return False

at_ip = req.get_param("at_ip", required=False)
if at_ip and not validate_ip(at_ip):
    raise ValueError("Invalid IP address provided")
resp.body = json.dumps(blaster_db.get_new_blasters(at_ip=at_ip))



# Resource to interact with all discovered Blasters
Expand Down
12 changes: 10 additions & 2 deletions app/db_helpers/blaster_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,18 @@ def discover_blasters(timeout):
]


def get_new_blasters(timeout=DISCOVERY_TIMEOUT):
def get_new_blasters(at_ip=None, timeout=DISCOVERY_TIMEOUT):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider adding error handling for broadlink.hello(at_ip) call

The function should handle potential exceptions or errors that may occur when calling broadlink.hello(at_ip). This will improve the robustness of the code.

def get_new_blasters(at_ip=None, timeout=DISCOVERY_TIMEOUT):
    try:
        cnt = 0
        discovered = []
        if at_ip:
            broadlink.hello(at_ip)
    except Exception as e:
        logging.error(f"Error discovering blasters: {e}")
        return []

cnt = 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion: Remove unused variable 'cnt'

The 'cnt' variable is initialized but never used. Consider removing it to improve code clarity.

Suggested change
cnt = 0
def get_new_blasters(at_ip=None, timeout=DISCOVERY_TIMEOUT):
discovered = []

discovered = []

for blaster in discover_blasters(timeout=timeout):
if at_ip:
d = broadlink.hello(at_ip)
if d:
discovered.append(d)
else:
discovered = discover_blasters(timeout=timeout)

for blaster in discovered:
mac_hex = enc_hex(blaster.mac)
mac = friendly_mac_from_hex(mac_hex)
check_blaster = Blaster.get_or_none(
Expand Down