From fca55edf172e11fb49909f981c9eb0f7573c2580 Mon Sep 17 00:00:00 2001 From: "pls.153" Date: Thu, 4 Jan 2024 15:39:53 +0100 Subject: [PATCH] example 'meshtastic': add option to change channel name; revisions --- examples/meshtastic/hardware/radio.htm | 12 ++--- examples/meshtastic/lisp/lora.lisp | 50 +++++++++++++------ examples/meshtastic/lisp/main.lisp | 13 +++-- examples/meshtastic/lisp/messages.lisp | 5 +- examples/meshtastic/lisp/package.lisp | 3 ++ examples/meshtastic/lisp/ui-vars.lisp | 8 +++ examples/meshtastic/qml/ext/Group.qml | 19 +++++++ examples/meshtastic/qml/ext/Help.qml | 8 +-- .../meshtastic/qml/ext/dialogs/Confirm.qml | 11 ---- .../qml/ext/dialogs/ConfirmMobile.qml | 11 ---- .../meshtastic/qml/ext/dialogs/Dialogs.qml | 20 +++++++- examples/meshtastic/qml/ext/dialogs/Input.qml | 44 ++++++++++++++++ .../qml/ext/dialogs/InputMobile.qml | 47 +++++++++++++++++ examples/meshtastic/qml/main.qml | 14 +++++- 14 files changed, 211 insertions(+), 54 deletions(-) create mode 100644 examples/meshtastic/qml/ext/dialogs/Input.qml create mode 100644 examples/meshtastic/qml/ext/dialogs/InputMobile.qml diff --git a/examples/meshtastic/hardware/radio.htm b/examples/meshtastic/hardware/radio.htm index 76357c2..eb0decc 100644 --- a/examples/meshtastic/hardware/radio.htm +++ b/examples/meshtastic/hardware/radio.htm @@ -23,13 +23,13 @@
  • toggle switch (no standby consumption)
  • antenna (bendable 90°) either 868 MHz (Europe) or 915 MHz (USA) + pigtail (IPEX-SMA) -

    Make sure both antenna and pigtail match, so they must be both SMA, or alternatively both RP-SMA.

    +

    Make sure both antenna and pigtail match, so they must be both SMA, or alternatively both RP-SMA.

    All parts above combined cost me around 50€.

    I used a soldering iron, a hot glue gun, a step drill bit, double sided tape.


    Antennas

    - Important: never power on your radio without a mounted antenna, this can destroy your hardware (power is reflected back to the radio). + Important: never power on your radio without a mounted antenna, this can destroy your hardware (power is reflected back to the radio).

    A good antenna is crucial for the radio to function properly. @@ -66,7 +66,7 @@ The antenna needs to be in vertical position while testing, so it's best practice to build a little stand for it, so one can test without touching the circuit, which would inevitably falsify the measurements.

    - It's highly recommended to only trust specialized shops (mouser, RAK store) for antennas, because there is simply too much mass produced garbage out there (talking from experience). + It's highly recommended to only trust specialized shops (Mouser, RAK store) for antennas, because there is simply too much mass produced garbage out there (talking from experience).

    If an antenna is totally off when I measure it, I like to dissect it. @@ -77,7 +77,7 @@


    Line of Sight

    To easily find out if two places are within line of sight, you can use this -
    Path Profiler: +

    Path Profiler


    line of sight @@ -93,9 +93,7 @@

    The RAK store has this nice enclosure where there is enough space for both a 18650 battery and a RAK 19003 Mini Board.

    -

    - (The above combination is not supported by the mounting kit, so this is just a personal hack, as you can see if you zoom in on the details.) -

    +

    The above combination is not supported by the mounting kit, so this is just a personal hack, as you can see if you zoom in on the details.


    diff --git a/examples/meshtastic/lisp/lora.lisp b/examples/meshtastic/lisp/lora.lisp index ffa5ea9..af15de4 100644 --- a/examples/meshtastic/lisp/lora.lisp +++ b/examples/meshtastic/lisp/lora.lisp @@ -3,18 +3,21 @@ (defvar *settings* (list :region :eu-868 :modem-preset :long-fast)) -(defvar *my-channel-name* "cl-app") ; max 12 bytes -(defvar *my-channel* nil) -(defvar *channels* nil) -(defvar *my-node-info* nil) -(defvar *node-infos* nil) -(defvar *receiver* nil) -(defvar *config-lora* nil) -(defvar *ble-names* nil) -(defvar *print-json* t) +(defvar *channel-name* nil) +(defvar *my-channel* nil) +(defvar *channels* nil) +(defvar *my-node-info* nil) +(defvar *node-infos* nil) +(defvar *receiver* nil) +(defvar *config-lora* nil) +(defvar *ble-names* nil) +(defvar *print-json* t) (defun ini () - (setf *receiver* (app:setting :latest-receiver))) + (setf *receiver* (app:setting :latest-receiver) + *channel-name* (or (app:setting :channel-name) + "cl-app")) + (q> |text| ui:*channel-name* *channel-name*)) ;;; header @@ -213,9 +216,9 @@ (if (x:starts-with ":e" text) ; 'echo' (progn (setf echo-text (subseq text #.(length ":e"))) - (qsingle-shot 1000 (lambda () (send-message (x:cc "echo:" echo-text))))) + (qsingle-shot 1000 (lambda () (send-message (x:cc ":e" echo-text))))) (progn - (when (x:starts-with "echo:" text) + (when (x:starts-with ":e" text) (setf text (msg:echo-message text (me:from packet) (me:rx-snr packet) (me:rx-rssi packet)))) (msg:add-message (list :receiver (my-name) @@ -291,7 +294,7 @@ (setf *config-complete* t) (q> |playing| ui:*busy* nil) (qlog "config-complete id: ~A" *config-id*) - (unless (string= *my-channel-name* + (unless (string= *channel-name* (me:name (me:settings *my-channel*))) (qlater 'config-device)))))) (setf *received* nil))) @@ -347,7 +350,7 @@ ;; channel settings for direct messages (set-channel (me:make-channel :settings (me:make-channel-settings - :name *my-channel-name* + :name *channel-name* :psk (to-bytes (list 1))) ; encrypted with fixed (known) key :role :primary)) (change-lora-config)) @@ -397,6 +400,25 @@ (group:receiver-changed) (values)) +(defun edit-channel-name () ; see QML + (if *config-complete* + (app:input-dialog + (tr "Channel name:") 'channel-name-changed + :title (tr "Name") + :text *channel-name* + :max-length #.(float 12)) + (app:message-dialog (tr "Radio not ready yet.")))) + +(defun channel-name-changed (ok) + (when ok + (let ((name (q< |text| ui:*dialog-line-edit*))) + (when (and (not (x:empty-string name)) + (string/= name *channel-name*)) + (setf *channel-name* name) + (q> |text| ui:*channel-name* *channel-name*) + (app:change-setting :channel-name name) + (config-device))))) + (defun keywords (name) (pr:enum-keywords (ecase name (:modem-preset diff --git a/examples/meshtastic/lisp/main.lisp b/examples/meshtastic/lisp/main.lisp index 59d1c8d..133444a 100644 --- a/examples/meshtastic/lisp/main.lisp +++ b/examples/meshtastic/lisp/main.lisp @@ -123,10 +123,17 @@ (defun message-dialog (text) (qjs |message| ui:*dialogs* text)) -(defun confirm-dialog (title text callback &key from to value) +(defun confirm-dialog (text callback) (qjs |confirm| ui:*dialogs* - title text (x:callback-name callback) - from to value)) ; for (optional) SpinBox + text (x:callback-name callback))) + +(defun input-dialog (label callback &key (title "") + text (max-length #.(float 32767)) + from to value) + (qjs |input| ui:*dialogs* + title label (x:callback-name callback) + text max-length ; string (line edit) + from to value)) ; integer (spin box) ;;; backup/restore all app data diff --git a/examples/meshtastic/lisp/messages.lisp b/examples/meshtastic/lisp/messages.lisp index 6f648d2..a068210 100644 --- a/examples/meshtastic/lisp/messages.lisp +++ b/examples/meshtastic/lisp/messages.lisp @@ -142,8 +142,9 @@ (values)) (defun font-size-dialog () - (app:confirm-dialog - (tr "Size") (tr "Message font size:") 'font-size-changed + (app:input-dialog + (tr "Message font size:") 'font-size-changed + :title (tr "Size") :from 10.0 :to 48.0 :value (float (or (app:setting :message-font-size) diff --git a/examples/meshtastic/lisp/package.lisp b/examples/meshtastic/lisp/package.lisp index 974994b..e1e523a 100644 --- a/examples/meshtastic/lisp/package.lisp +++ b/examples/meshtastic/lisp/package.lisp @@ -8,6 +8,7 @@ #:icon-press-and-hold #:in-data-path #:ini + #:input-dialog #:load-settings #:message-dialog #:make-backup @@ -30,6 +31,7 @@ #:+broadcast-id+ #:*broadcast-name* #:*channel* + #:*channel-name* #:*channels* #:*config-complete* #:*config-lora* @@ -48,6 +50,7 @@ #:change-region #:change-modem-preset #:channel-to-url + #:edit-channel-name #:get-node-config #:ini #:keywords diff --git a/examples/meshtastic/lisp/ui-vars.lisp b/examples/meshtastic/lisp/ui-vars.lisp index b75d4f8..e94e3b8 100644 --- a/examples/meshtastic/lisp/ui-vars.lisp +++ b/examples/meshtastic/lisp/ui-vars.lisp @@ -5,7 +5,9 @@ (:export #:*add-manual-marker* #:*busy* + #:*channel-name* #:*dialogs* + #:*dialog-line-edit* #:*dialog-spin-box* #:*edit* #:*emojis* @@ -14,6 +16,7 @@ #:*group* #:*group-icon* #:*group-view* + #:*help* #:*hourglass* #:*location* #:*main-view* @@ -21,6 +24,7 @@ #:*map-loader* #:*map-view* #:*markers* + #:*menu* #:*messages* #:*message-view* #:*modem* @@ -37,7 +41,9 @@ (defparameter *add-manual-marker* "add_manual_marker") (defparameter *busy* "busy") +(defparameter *channel-name* "channel_name") (defparameter *dialogs* "dialogs") +(defparameter *dialog-line-edit* "dialog_line_edit") (defparameter *dialog-spin-box* "dialog_spin_box") (defparameter *edit* "edit") (defparameter *emojis* "emojis") @@ -46,6 +52,7 @@ (defparameter *group* "group") (defparameter *group-icon* "group_icon") (defparameter *group-view* "group_view") +(defparameter *help* "help") (defparameter *hourglass* "hourglass") (defparameter *location* "location") (defparameter *map* "map") @@ -53,6 +60,7 @@ (defparameter *map-view* "map_view") (defparameter *markers* "markers") (defparameter *main-view* "main_view") +(defparameter *menu* "menu") (defparameter *messages* "messages") (defparameter *message-view* "message_view") (defparameter *modem* "modem") diff --git a/examples/meshtastic/qml/ext/Group.qml b/examples/meshtastic/qml/ext/Group.qml index a831525..b9489d0 100644 --- a/examples/meshtastic/qml/ext/Group.qml +++ b/examples/meshtastic/qml/ext/Group.qml @@ -34,6 +34,7 @@ Rectangle { id: view objectName: "group_view" anchors.topMargin: rowModem.height + anchors.bottomMargin: channel.height anchors.fill: parent anchors.margins: 9 spacing: 9 @@ -43,6 +44,24 @@ Rectangle { currentIndex: -1 } + Rectangle { + id: channel + anchors.bottom: parent.bottom + width: parent.width + height: 28 + color: "#555" + + Text { + objectName: "channel_name" + anchors.centerIn: parent + font.pixelSize: 16 + font.family: fontText.name + font.weight: Font.DemiBold + color: rect.color + text: "cl-app" + } + } + ListModel { id: group objectName: "group" diff --git a/examples/meshtastic/qml/ext/Help.qml b/examples/meshtastic/qml/ext/Help.qml index bd10fd7..ec7214e 100644 --- a/examples/meshtastic/qml/ext/Help.qml +++ b/examples/meshtastic/qml/ext/Help.qml @@ -52,14 +52,16 @@ In the rare case your radio is not found, you may restart device discovery by a
    Group

    -Here you see the list of all persons. Every person is associated to a radio. This view is populated automatically. +Here you can see the list of all radios using your same channel name. Every radio represents a person. This view is populated automatically.

    Choose 'Broadcast' (on top) to send a message to every person in the group.

    -You can set a name to every person associated to a radio, which defaults to -'Anonym': a press-and-hold on the name will enter edit mode. +You can set a name to every radio/person listed here, which defaults to 'Anonym': a press-and-hold on the name will enter edit mode. +

    +

    +In the main menu you can change your channel name (which defaults to 'cl-app'). Only radios which share the same channel name are able to exchange messages.

    A tap on the location item on the right shows a map with all known positions of the persons. The map is cached automatically for offline usage, which means: once you visited a place on the map, it will remain available even without internet connection. diff --git a/examples/meshtastic/qml/ext/dialogs/Confirm.qml b/examples/meshtastic/qml/ext/dialogs/Confirm.qml index ea5939a..65ce0ea 100644 --- a/examples/meshtastic/qml/ext/dialogs/Confirm.qml +++ b/examples/meshtastic/qml/ext/dialogs/Confirm.qml @@ -6,9 +6,6 @@ Dialog { standardButtons: Dialog.Ok | Dialog.Cancel property alias text: message.text - property alias from: spinBox.from - property alias to: spinBox.to - property alias value: spinBox.value property string callback Column { @@ -19,14 +16,6 @@ Dialog { id: message width: parent.width wrapMode: Text.Wrap - visible: (text !== "") - } - - SpinBox { - id: spinBox - objectName: "dialog_spin_box" - anchors.horizontalCenter: parent.horizontalCenter - visible: !!value } } diff --git a/examples/meshtastic/qml/ext/dialogs/ConfirmMobile.qml b/examples/meshtastic/qml/ext/dialogs/ConfirmMobile.qml index 116e805..67aa727 100644 --- a/examples/meshtastic/qml/ext/dialogs/ConfirmMobile.qml +++ b/examples/meshtastic/qml/ext/dialogs/ConfirmMobile.qml @@ -8,9 +8,6 @@ Dialog { standardButtons: Dialog.Ok | Dialog.Cancel property alias text: message.text - property alias from: spinBox.from - property alias to: spinBox.to - property alias value: spinBox.value property string callback Column { @@ -22,14 +19,6 @@ Dialog { width: parent.width wrapMode: Text.Wrap font.pixelSize: 18 - visible: (text !== "") - } - - SpinBox { - id: spinBox - objectName: "dialog_spin_box" - anchors.horizontalCenter: parent.horizontalCenter - visible: !!value } } diff --git a/examples/meshtastic/qml/ext/dialogs/Dialogs.qml b/examples/meshtastic/qml/ext/dialogs/Dialogs.qml index e0ffe8a..238dac0 100644 --- a/examples/meshtastic/qml/ext/dialogs/Dialogs.qml +++ b/examples/meshtastic/qml/ext/dialogs/Dialogs.qml @@ -23,7 +23,7 @@ Item { loader.item.open() } - function confirm(title, text, callback, from, to, value) { + function confirm(text, callback) { loader.active = false // force reload if (rootItem.mobile) { loader.source = "ConfirmMobile.qml" @@ -31,9 +31,25 @@ Item { loader.source = "Confirm.qml" } loader.active = true - loader.item.title = title loader.item.text = text loader.item.callback = callback + rootItem.showKeyboard(false) + loader.item.open() + } + + function input(title, label, callback, text, maxLength, from, to, value) { + loader.active = false // force reload + if (rootItem.mobile) { + loader.source = "InputMobile.qml" + } else { + loader.source = "Input.qml" + } + loader.active = true + loader.item.title = title + loader.item.label = label + loader.item.callback = callback + loader.item.text = text + loader.item.maxLength = maxLength loader.item.from = from loader.item.to = to loader.item.value = value diff --git a/examples/meshtastic/qml/ext/dialogs/Input.qml b/examples/meshtastic/qml/ext/dialogs/Input.qml new file mode 100644 index 0000000..f6ff133 --- /dev/null +++ b/examples/meshtastic/qml/ext/dialogs/Input.qml @@ -0,0 +1,44 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Dialogs 1.3 + +Dialog { + standardButtons: Dialog.Ok | Dialog.Cancel + + property alias label: label.text + property alias text: edit.text + property alias maxLength: edit.maximumLength + property alias from: spinBox.from + property alias to: spinBox.to + property alias value: spinBox.value + property string callback + + Column { + width: parent.width + spacing: 5 + + Text { + id: label + width: parent.width + wrapMode: Text.Wrap + visible: (text !== "") + } + + TextField { + id: edit + objectName: "dialog_line_edit" + width: parent.width + visible: !spinBox.visible + } + + SpinBox { + id: spinBox + objectName: "dialog_spin_box" + anchors.horizontalCenter: parent.horizontalCenter + visible: !!value + } + } + + onAccepted: Lisp.call(callback, true) + onRejected: Lisp.call(callback, false) +} diff --git a/examples/meshtastic/qml/ext/dialogs/InputMobile.qml b/examples/meshtastic/qml/ext/dialogs/InputMobile.qml new file mode 100644 index 0000000..7feafc1 --- /dev/null +++ b/examples/meshtastic/qml/ext/dialogs/InputMobile.qml @@ -0,0 +1,47 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 + +Dialog { + anchors.centerIn: parent + font.pixelSize: 18 + modal: true + standardButtons: Dialog.Ok | Dialog.Cancel + + property alias label: label.text + property alias text: edit.text + property alias maxLength: edit.maximumLength + property alias from: spinBox.from + property alias to: spinBox.to + property alias value: spinBox.value + property string callback + + Column { + width: parent.width + spacing: 5 + + Text { + id: label + width: parent.width + wrapMode: Text.Wrap + font.pixelSize: 18 + visible: (text !== "") + } + + TextField { + id: edit + objectName: "dialog_line_edit" + width: parent.width + visible: !spinBox.visible + } + + SpinBox { + id: spinBox + objectName: "dialog_spin_box" + anchors.horizontalCenter: parent.horizontalCenter + visible: !!value + } + } + + onAccepted: Lisp.call(callback, true) + onRejected: Lisp.call(callback, false) +} diff --git a/examples/meshtastic/qml/main.qml b/examples/meshtastic/qml/main.qml index 1335133..7e9cef9 100644 --- a/examples/meshtastic/qml/main.qml +++ b/examples/meshtastic/qml/main.qml @@ -23,20 +23,32 @@ Item { Menu { id: menu + objectName: "menu" + + function show() { popup(0, headerHeight) } Ext.MenuItem { + objectName: "help" text: qsTr("Help") onTriggered: help.active ? help.item.enabled = !help.item.enabled : help.active = true } + Ext.MenuItem { + text: qsTr("Channel name...") + onTriggered: Lisp.call("lora:edit-channel-name") + enabled: (view.currentIndex === 0) + } + Ext.MenuItem { text: qsTr("Message font size...") onTriggered: Lisp.call("msg:font-size-dialog") + enabled: (view.currentIndex === 1) } Ext.MenuItem { text: qsTr("Update group/nodes") onTriggered: Lisp.call("lora:get-node-config") + enabled: (view.currentIndex === 0) } Ext.MenuItem { @@ -60,7 +72,7 @@ Item { MouseArea { anchors.fill: parent - onClicked: menu.popup(0, headerHeight) + onClicked: menu.show() } }