2 LuCI model for mosquitto MQTT broker configuration management
3 Copyright eTactica ehf, 2018
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
13 local datatypes = require("luci.cbi.datatypes")
14 local _ = luci.i18n.translate
16 --- Like a Flag, but with an option to remove/set to default.
17 local function OptionalFlag(section, key, title, description)
18 local o = section:option(ListValue, key, title, description)
20 o:value("", "Default")
21 o:value("1", "Enabled")
22 o:value("0", "Disabled")
26 m = Map("mosquitto", _("Mosquitto MQTT Broker"),
27 _([[mosquitto - the <a href='http://www.mosquitto.org'>blood thirsty</a>
28 MQTT messaging broker. Note, only some of the available configuration files
29 are supported at this stage, use the checkbox below to use config generated
30 by this page, or the stock mosquitto configuration file in
31 /etc/mosquitto/mosquitto.conf]]))
33 s = m:section(TypedSection, "owrt", "OpenWRT")
35 p = s:option(Flag, "use_uci", _("Use this LuCI configuration page"),
36 _([[If checked, mosquitto runs with a config generated
37 from this page. (Or from UCI directly) If unchecked, mosquitto
38 runs with the config in /etc/mosquitto/mosquitto.conf
39 (and this page is ignored)]]))
41 s = m:section(TypedSection, "mosquitto", "Mosquitto")
44 p = s:option(MultiValue, "log_dest", _("Log destination"),
45 _("You can have multiple, but 'none' will override all others"))
46 p:value("stderr", "stderr")
47 p:value("stdout", "stdout")
48 p:value("syslog", "syslog")
49 p:value("topic", "$SYS/broker/log/[severity]")
50 p:value("none", "none")
52 OptionalFlag(s, "no_remote_access", _("Disallow remote access to this broker"),
53 _([[Outbound bridges will still work, but this will make the primary listener
54 only available from localhost]]))
57 o = s:option(Value, "sys_interval", _("Time in seconds between updates of the $SYS tree"), _("Set to zero to disable"))
58 o.datatype = "uinteger"
61 o = s:option(Value, "max_inflight_messages", _("Max Inflight Messages"), _("Limit for message allowed inflight"))
62 o.datatype = "uinteger"
64 o = s:option(Value, "max_queued_messages", _("Max Queued Messages"), _("Limit for message queue when offline"))
65 o.datatype = "uinteger"
67 o = s:option(Value, "max_queued_bytes", _("Max Queued bytes"), _("Limit for message queue when offline, zero to disable)"))
68 o.datatype = "uinteger"
72 s = m:section(TypedSection, "persistence", _("Persistence"))
75 s:option(Flag, "persistence", _("Persistence enabled"), _("Should persistence to disk be enabled at all")).rmempty = false
76 o = s:option(Value, "client_expiration", _("Client expiration"), _("Remove persistent clients if they haven't reconnected in this period, eg 6h, 3d, 2w"))
78 o:depends("persistence", true)
79 o = OptionalFlag(s, "autosave_on_changes", _("Autosave on changes"), _("Autosave interval applies to change counts instead of time"))
80 o:depends("persistence", true)
81 o = s:option(Value, "autosave_interval", _("Autosave interval"), _("Save persistence file after this many seconds or changes"))
83 o:depends("persistence", true)
84 o = s:option(Value, "file", _("Persistent file name"))
86 o:depends("persistence", true)
87 o = s:option(Value, "location", _("Persistent file path (with trailing/)"), _("Path to persistent file"))
89 o:depends("persistence", true)
91 s = m:section(TypedSection, "listener", _("Listeners"), _("You can configure additional listeners here"))
94 s:option(Value, "port", _("Port")).datatype = "port"
96 o = s:option(ListValue, "protocol", _("Protocol to use when listening"))
97 o:value("", "Default")
98 o:value("mqtt", _("MQTT"))
99 o:value("websockets", _("WebSockets"))
101 s:option(Value, "http_dir", _("http_dir to serve on websockets listeners")).optional = true
102 OptionalFlag(s, "use_username_as_clientid", "use_username_as_clientid")
103 o = s:option(Value, "cafile", _("CA file path"))
106 o = s:option(Value, "capath", _("CA path to search"))
108 o.datatype = "directory"
109 o = s:option(Value, "certfile", _("server certificate file (PEM encoded)"))
112 o = s:option(Value, "keyfile", _("keyfile (PEM encoded)"))
116 o = s:option(ListValue, "tls_version", _("TLS Version"),
117 _("Depends on your openssl version, empty to support all"))
119 o:value("", "Default")
124 OptionalFlag(s, "require_certificate", _("Require clients to present a certificate"))
125 OptionalFlag(s, "use_identity_as_username", "use_identity_as_username")
126 s:option(Value, "crlfile", _("CRL to use if require_certificate is enabled")).optional = true
127 s:option(Value, "ciphers", _("Ciphers control. Should match 'openssl ciphers' format")).optional = true
128 s:option(Value, "psk_hint", _("PSK Hint to provide to connecting clients")).optional = true
130 -- we want to allow multiple bridge sections
131 s = m:section(TypedSection, "bridge", _("Bridges"),
132 _("You can configure multiple bridge connections here"))
136 conn = s:option(Value, "connection", _("Connection name"),
137 _("unique name for this bridge configuration"))
139 local function validate_address(self, value)
140 local host, port = unpack(luci.util.split(value, ":"))
141 if (datatypes.host(host)) then
142 if port and #port then
143 if not datatypes.port(port) then
144 return nil, _("Please enter a valid port after the :")
149 return nil, _("Please enter a hostname or an IP address")
152 addr = s:option(Value, "address", _("address"), _("address[:port] of remote broker"))
153 addr.datatype = "string"
154 addr.validate = validate_address
156 -- TODO - make the in/out/both a dropdown/radio or something....
157 topics = s:option(DynamicList, "topic", _("topic"),
158 _("full topic string for mosquitto.conf, eg: 'power/# out 2'"))
160 OptionalFlag(s, "cleansession", _("Clean session"))
161 OptionalFlag(s, "notifications", _("notifications"),
162 _("Attempt to notify the local and remote broker of connection status, defaults to $SYS/broker/connections/<clientid>/state"))
163 s:option(Value, "notification_topic", _("Topic to use for local+remote remote for notifications.")).optional = true
164 OptionalFlag(s, "notification_local_only", _("Notifications local only"), _("Bridge connection states should only be published locally"))
166 s:option(Value, "remote_clientid", _("Client id to use on remote end of this bridge connection")).optional = true
167 s:option(Value, "local_clientid", _("Client id to use locally. Important when bridging to yourself")).optional = true
168 o = s:option(Value, "keepalive_interval", _("Keepalive interval for this bridge"))
169 o.datatype = "uinteger"
171 o = s:option(ListValue, "start_type", _("How should this bridge be started"))
173 o:value("", "Default")
174 o:value("automatic", _("Automatic, includes restarts"))
175 o:value("lazy", _("Automatic, but stopped when not used"))
176 o:value("once", _("Automatic, but no restarts"))
177 o = s:option(Value, "restart_timeout", _("How long to wait before reconnecting"))
178 o.datatype = "uinteger"
180 o = s:option(Value, "idle_timeout", _("How long to wait before disconnecting"))
181 o.datatype = "uinteger"
183 o = s:option(Value, "threshold", _("How many messages to queue before restarting lazy bridge"))
184 o.datatype = "uinteger"
187 OptionalFlag(s, "try_private", "try_private",
188 _("attempt to notify the remote broker that this is a bridge, not all brokers support this."))
189 s:option(Value, "remote_username", _("Remote username")).optional = true
190 o = s:option(Value, "remote_password", _("Remote password"))
194 s:option(Value, "identity", _("PSK Bridge Identity"), _("Identity for TLS-PSK")).optional = true
196 -- no hex validation available in datatypes
197 local function validate_psk_key(self, value)
198 if (value:match("^[a-fA-F0-9]+$")) then
201 return nil, _("Only hex numbers are allowed (use A-F characters and 0-9 digits)")
204 psk_key = s:option(Value, "psk", _("Bridge PSK"), _("Key for TLS-PSK"))
205 psk_key.password = true
206 psk_key.optional = true
207 psk_key.datatype = "string"
208 psk_key.validate = validate_psk_key
210 b_tls_version = s:option(ListValue, "tls_version", _("TLS Version"),
211 _("The remote broker must support the same version of TLS for the connection to succeed."))
212 b_tls_version:value("", "Default")
213 b_tls_version:value("tlsv1.1")
214 b_tls_version:value("tlsv1.2")
215 b_tls_version:value("tlsv1.3")
216 b_tls_version.optional = true
218 o = s:option(Value, "cafile", _("Path to CA file"))
221 o = s:option(Value, "capath", _("Directory to search for CA files"))
223 o.datatype = "directory"
224 o = s:option(Value, "certfile", _("Path to PEM encoded server certificate file"))
227 o = s:option(Value, "keyfile", _("Path to PEM encoded keyfile"))