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
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ config filters
config concentratord
option event_url 'ipc:///tmp/gateway_relay_event'
option command_url 'ipc:///tmp/gateway_relay_command'

config callbacks 'callbacks'
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ config mqtt
option qos '0'

config filters

config callbacks 'callbacks'
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ config filters
config concentratord
option event_url 'ipc:///tmp/concentratord_slot1_event'
option command_url 'ipc:///tmp/concentratord_slot1_command'

config callbacks 'callbacks'
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ config filters
config concentratord
option event_url 'ipc:///tmp/concentratord_slot2_event'
option command_url 'ipc:///tmp/concentratord_slot2_command'

config callbacks 'callbacks'
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ configure() {

conf_rule_commands "$config_name"
conf_rule_metadata "$config_name"
conf_rule_callbacks "$config_name"
}

conf_rule_concentratord() {
Expand All @@ -47,7 +48,7 @@ conf_rule_concentratord() {
conf_rule_mqtt() {
local cfg="$1"
local config_name="$2"
local topic_prefix json server username password qos clean_session client_id ca_cert tls_cert tls_key
local topic_prefix json server username password qos clean_session keep_alive_interval client_id ca_cert tls_cert tls_key reconnect_interval

config_get topic_prefix $cfg topic_prefix
config_get json $cfg json
Expand All @@ -57,9 +58,11 @@ conf_rule_mqtt() {
config_get qos $cfg qos
config_get_bool clean_session $cfg clean_session
config_get client_id $cfg client_id
config_get keep_alive_interval $cfg keep_alive_interval
config_get ca_cert $cfg ca_cert
config_get tls_cert $cfg tls_cert
config_get tls_key $cfg tls_key
config_get reconnect_interval $cfg reconnect_interval

if [ "$json" = "1" ]; then
json="true"
Expand All @@ -73,6 +76,10 @@ conf_rule_mqtt() {
clean_session="false"
fi

if [ "$keep_alive_interval" = "" ]; then
keep_alive_interval="30s"
fi

if [ "$ca_cert" != "" ]; then
echo "$ca_cert" >/var/etc/$config_name/ca.pem
ca_cert="/var/etc/$config_name/ca.pem"
Expand All @@ -98,26 +105,39 @@ conf_rule_mqtt() {
qos=$qos
clean_session=$clean_session
client_id="$client_id"
keep_alive_interval="$keep_alive_interval"
ca_cert="$ca_cert"
tls_cert="$tls_cert"
tls_key="$tls_key"
EOF

if [ "$reconnect_interval" != "" ]; then
echo "reconnect_interval=\"$reconnect_interval\"" >>/var/etc/$config_name/chirpstack-mqtt-forwarder.toml
fi

}

conf_rule_filters() {
local cfg="$1"
local config_name="$2"
local forward_crc_ok forward_crc_invalid forward_crc_missing lorawan_only

config_get lorawan_only $cfg lorawan_only
config_get_bool forward_crc_ok $cfg forward_crc_ok true
config_get_bool forward_crc_invalid $cfg forward_crc_invalid false
config_get_bool forward_crc_missing $cfg forward_crc_missing false
config_get_bool lorawan_only $cfg lorawan_only

if [ "$lorawan_only" = "1" ]; then
lorawan_only="true"
else
lorawan_only="false"
fi
# convert uci bool (1 or 0) to toml bool (true or false)
[ "$forward_crc_invalid" = "1" ] && forward_crc_invalid="true" || forward_crc_invalid="false"
[ "$forward_crc_missing" = "1" ] && forward_crc_missing="true" || forward_crc_missing="false"
[ "$forward_crc_ok" = "1" ] && forward_crc_ok="true" || forward_crc_ok="false"
[ "$lorawan_only" = "1" ] && lorawan_only="true" || lorawan_only="false"

cat >>/var/etc/$config_name/chirpstack-mqtt-forwarder.toml <<-EOF
[backend.filters]
forward_crc_ok=$forward_crc_ok
forward_crc_invalid=$forward_crc_invalid
forward_crc_missing=$forward_crc_missing
lorawan_only=$lorawan_only
dev_addr_prefixes=[
EOF
Expand Down Expand Up @@ -173,7 +193,6 @@ conf_rule_metadata() {
EOF

config_foreach conf_command "metadata" "$config_name"

}

# Foreach config 'type' 'key'
Expand Down Expand Up @@ -237,3 +256,40 @@ conf_command_arg() {

echo -n "\"$1\"", >>/var/etc/$config_name/chirpstack-mqtt-forwarder.toml
}

conf_rule_callbacks() {
local config_name="$2"

cat >>/var/etc/$config_name/chirpstack-mqtt-forwarder.toml <<-EOF
[callbacks]
EOF

# on_mqtt_connected
cat >>/var/etc/$config_name/chirpstack-mqtt-forwarder.toml <<-EOF
on_mqtt_connected=[
EOF

config_list_foreach 'callbacks' 'on_mqtt_connected' conf_rule_callbacks_on_mqtt "$config_name"

cat >>/var/etc/$config_name/chirpstack-mqtt-forwarder.toml <<-EOF
]
EOF

# on_mqtt_connection_error
cat >>/var/etc/$config_name/chirpstack-mqtt-forwarder.toml <<-EOF
on_mqtt_connection_error=[
EOF

config_list_foreach 'callbacks' 'on_mqtt_connection_error' conf_rule_callbacks_on_mqtt "$config_name"

cat >>/var/etc/$config_name/chirpstack-mqtt-forwarder.toml <<-EOF
]
EOF
}

conf_rule_callbacks_on_mqtt() {
local config_name="$2"
cat >>/var/etc/$config_name/chirpstack-mqtt-forwarder.toml <<-EOF
"$1",
EOF
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,50 @@ return baseclass.extend({
return "Enter a valid MQTT server address.";
};

// keep alive interval
o = s.option(
form.Value,
"keep_alive_interval",
_("Keep Alive Interval"),
_(
"Defines the maximum time that should pass without communication between the client and server",
),
);
o.optional = true;
o.validate = function (section_id, value) {
if (!value) {
return true;
}

if (/^\d+[smhd]$/.test(value.trim())) {
return true;
}

return "Enter a valid duration (e.g. 30s, 5m, 1h, 1d)";
};

// reconnect_interval
o = s.option(
form.Value,
"reconnect_interval",
_("Reconnect Interval"),
_(
"defines the reconnection interval to the MQTT broker in case of network issues",
),
);
o.optional = true;
o.validate = function (section_id, value) {
if (!value) {
return true;
}

if (/^\d+[smhd]$/.test(value.trim())) {
return true;
}

return "Enter a valid duration (e.g. 30s, 5m, 1h, 1d)";
};

// username
o = s.option(
form.Value,
Expand Down Expand Up @@ -154,6 +198,42 @@ return baseclass.extend({
s = m.section(form.TypedSection, "filters", _("Filter configuration"));
s.anonymous = true;

// forward_crc_ok
o = s.option(
form.Flag,
"forward_crc_ok",
_("Forward CRC ok"),
_(
"Forward LoRaWAN frame when CRC is valid",
),
);
o.default = o.enabled;
o.rmempty = false;

// forward_crc_invalid
o = s.option(
form.Flag,
"forward_crc_invalid",
_("Forward CRC invalid"),
_(
"Forward LoRaWAN frame when CRC is invalid",
),
);
o.default = o.disabled;
o.rmempty = false;

// forward_crc_missing
o = s.option(
form.Flag,
"forward_crc_missing",
_("Forward CRC missing"),
_(
"Forward LoRaWAN frame when CRC is missing",
),
);
o.default = o.disabled;
o.rmempty = false;

// LoRaWAN only
o = s.option(
form.Flag,
Expand All @@ -164,7 +244,7 @@ return baseclass.extend({
),
);

// DevAddr prefixs
// DevAddr prefixes
o = s.option(
form.DynamicList,
"dev_addr_prefix",
Expand All @@ -173,8 +253,30 @@ return baseclass.extend({
"Filter uplinks based on the configured DevAddr prefixes (e.g. '0000ff00/24'). If no filters have been configured, filtering is disabled.",
),
);
o.validate = function (section_id, value) {
if (value == null || value === "")
return true;

// DevEUI prefixes
var parts = value.split("/");

if (parts.length !== 2)
return _("Expected the format {hex}/{mask}, e.g. 0000ff00/24");

if (!/^[0-9a-fA-F]{8}$/.test(parts[0]))
return _("Invalid address '%s'/ must be exactly 8 hexadecimal digits").format(parts[0]);

if (!/^\d+$/.test(parts[1]))
return _("Invalid mask '/%s' must be a number").format(parts[1]);

// +parts[1] trick to convert str to number
if (+parts[1] > 32)
return _("Invalid mask '/%s' must be between 0 and 32").format(parts[1]);

return true;
};
o.rmempty = true;

// JoinEUI prefixes
o = s.option(
form.DynamicList,
"join_eui_prefix",
Expand All @@ -183,6 +285,28 @@ return baseclass.extend({
"Filter join-requests based on the configured JoinEUI prefixes (e.g. '0000ff0000000000/24'). If no filters have been configured, filtering is disabled.",
),
);
o.validate = function (section_id, value) {
if (value == null || value === "")
return true;

var parts = value.split("/");

if (parts.length !== 2)
return _("Expected the format {hex}/{mask}, e.g. 0000ff0000000000/24");

if (!/^[0-9a-fA-F]{16}$/.test(parts[0]))
return _("Invalid address '%s'/ must be exactly 16 hexadecimal digits").format(parts[0]);

if (!/^\d+$/.test(parts[1]))
return _("Invalid mask '/%s' must be a number").format(parts[1]);

// +parts[1] trick to convert str to number
if (+parts[1] > 64)
return _("Invalid mask '/%s' must be between 0 and 64").format(parts[1]);

return true;
};
o.rmempty = true;

// Commands
s = m.section(form.TypedSection, "commands", _("Commands"));
Expand Down Expand Up @@ -216,6 +340,30 @@ return baseclass.extend({
),
);

// force create section callbacks if it's missing
if (!uci.get(mqttForwarderConfig, "callbacks"))
uci.add(mqttForwarderConfig, "callbacks", "callbacks");

s = m.section(form.NamedSection, "callbacks", "callbacks", _("Callbacks"));

s.option(
form.DynamicList,
"on_mqtt_connected",
_("On mqtt Connected"),
_(
"Commands triggered when MQTT connected",
),
);

s.option(
form.DynamicList,
"on_mqtt_connection_error",
_("On mqtt Connection Error"),
_(
"Commands triggered when MQTT Connection is in Error",
),
);

return m.render();
},
});