Skip to content

Commit

Permalink
Add websockets transport mechanism to MQTT
Browse files Browse the repository at this point in the history
## Proposed change
Add websockets transport mechanism to MQTT.

An MQTT server is not always reachable only as raw TCP on port 1881; it can also be accessed as a WebSocket server, sometimes even behind a reverse proxy with TLS. Paho MQTT supports this feature, as does Mosquitto.

The default transport option was set to 'tcp', so this change will not affect an already configured Frigate app.

The configuration change is validated using a call to a pydantic library field validator.

This patch has been tested with Mosquitto 1.6 and 2.0, as well as with a server behind a reverse proxy on port 443 (requiring a TLS connection).

The docs/configuration/reference.md file has also been updated to reflect this change.

## Type of change

- [ ] Dependency upgrade
- [ ] Bugfix (non-breaking change which fixes an issue)
- [x] New feature
- [ ] Breaking change (fix/feature causing existing functionality to break)
- [ ] Code quality improvements to existing code
- [x] Documentation Update

## Additional information

- This PR fixes or closes issue: fixes #15600
- This PR is related to issue:

## Checklist

- [x] The code change is tested and works locally.
- [ ] Local tests pass. **Your PR cannot be merged unless tests pass**
- [x] There is no commented out code in this PR.
- [x] The code has been formatted using Ruff (`ruff format frigate`)
  • Loading branch information
VideoCurio committed Dec 19, 2024
1 parent 4af7520 commit 56a128b
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 1 deletion.
3 changes: 3 additions & 0 deletions docs/docs/configuration/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ mqtt:
host: mqtt.server.com
# Optional: port (default: shown below)
port: 1883
# Optional: MQTT transport mechanism (default: shown below)
# NOTE: must be tcp (raw MQTT) or websockets.
transport: tcp
# Optional: topic prefix (default: shown below)
# NOTE: must be unique if you are running multiple instances
topic_prefix: frigate
Expand Down
4 changes: 4 additions & 0 deletions frigate/comms/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,11 @@ def _on_disconnect(

def _start(self) -> None:
"""Start mqtt client."""
logger.info("MQTT transport mechanism: %s" % str(self.mqtt_config.transport))
self.client = mqtt.Client(
callback_api_version=CallbackAPIVersion.VERSION2,
client_id=self.mqtt_config.client_id,
transport=self.mqtt_config.transport,
)
self.client.on_connect = self._on_connect
self.client.on_disconnect = self._on_disconnect
Expand All @@ -180,6 +182,8 @@ def _start(self) -> None:
qos=1,
retain=True,
)
if self.mqtt_config.transport == "websockets":
self.client.ws_set_options(path="/mqtt")

# register callbacks
callback_types = [
Expand Down
10 changes: 9 additions & 1 deletion frigate/config/mqtt.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from pydantic import Field, ValidationInfo, model_validator
from pydantic import Field, ValidationInfo, model_validator, field_validator
from typing_extensions import Self

from frigate.const import FREQUENCY_STATS_POINTS
Expand All @@ -15,6 +15,7 @@ class MqttConfig(FrigateBaseModel):
enabled: bool = Field(default=True, title="Enable MQTT Communication.")
host: str = Field(default="", title="MQTT Host")
port: int = Field(default=1883, title="MQTT Port")
transport: str = Field(default="tcp", title="MQTT Transport Mechanism")
topic_prefix: str = Field(default="frigate", title="MQTT Topic Prefix")
client_id: str = Field(default="frigate", title="MQTT Client ID")
stats_interval: int = Field(
Expand All @@ -36,3 +37,10 @@ def user_requires_pass(self, info: ValidationInfo) -> Self:
if (self.user is None) != (self.password is None):
raise ValueError("Password must be provided with username.")
return self

@field_validator("transport")
@classmethod
def check_transport_mechanism(cls, v: str) -> str:
if v != "tcp" and v != "websockets":
raise ValueError("MQTT transport could only be tcp or websockets.")
return v

0 comments on commit 56a128b

Please sign in to comment.