Module: Meshtastic::Admin
- Defined in:
- lib/meshtastic/admin.rb,
lib/meshtastic/admin/config.rb,
lib/meshtastic/admin/channel.rb,
lib/meshtastic/admin/firmware.rb,
lib/meshtastic/admin/firmware/ble.rb,
lib/meshtastic/admin/firmware/hex.rb,
lib/meshtastic/admin/firmware/uf2.rb,
lib/meshtastic/admin/firmware/nordic_dfu.rb,
lib/meshtastic/admin/firmware/serial_bootloader.rb
Defined Under Namespace
Modules: Channel, Config, Firmware Classes: RoutingError
Constant Summary collapse
- SKIP =
%i[ message transport_obj to from channel want_ack hop_limit want_response port_num data via psks seconds owner long_name short_name index config_type module_config_type path node_num lat lon altitude time channel_settings channel_pb config module_config messages ringtone scale location event event_code kb_char touch_x touch_y ham call_sign tx_power frequency position ui_config contact value preserve_favorites last_packet_id pki_encrypted public_key topic qos retained timeout auto_session refresh_session ].freeze
- PAYLOAD_FIELDS =
Meshtastic::AdminMessage.descriptor.lookup_oneof('payload_variant').map { |field| field.name.to_sym }.freeze
Class Method Summary collapse
- .add_contact(opts = {}) ⇒ Object
- .authors ⇒ Object
- .backup_preferences(opts = {}) ⇒ Object
- .begin_edit(opts = {}) ⇒ Object
- .commit_edit(opts = {}) ⇒ Object
- .decode(opts = {}) ⇒ Object
- .delete_file(opts = {}) ⇒ Object
- .encode(opts = {}) ⇒ Object
- .enter_dfu(opts = {}) ⇒ Object
- .exit_simulator(opts = {}) ⇒ Object
- .factory_reset_config(opts = {}) ⇒ Object
- .factory_reset_device(opts = {}) ⇒ Object
- .get_canned_messages(opts = {}) ⇒ Object
- .get_channel(opts = {}) ⇒ Object
- .get_config(opts = {}) ⇒ Object
- .get_device_connection_status(opts = {}) ⇒ Object
- .get_device_metadata(opts = {}) ⇒ Object
- .get_module_config(opts = {}) ⇒ Object
- .get_node_remote_hardware_pins(opts = {}) ⇒ Object
- .get_owner(opts = {}) ⇒ Object
- .get_ringtone(opts = {}) ⇒ Object
- .get_ui_config(opts = {}) ⇒ Object
- .help ⇒ Object
- .key_verification(opts = {}) ⇒ Object
- .lockdown_auth(opts = {}) ⇒ Object
- .nodedb_reset(opts = {}) ⇒ Object
- .ota_request(opts = {}) ⇒ Object
- .reboot(opts = {}) ⇒ Object
- .reboot_ota(opts = {}) ⇒ Object
- .remove_backup_preferences(opts = {}) ⇒ Object
- .remove_by_nodenum(opts = {}) ⇒ Object
- .remove_favorite_node(opts = {}) ⇒ Object
- .remove_fixed_position(opts = {}) ⇒ Object
- .remove_ignored_node(opts = {}) ⇒ Object
- .request(opts = {}) ⇒ Object
- .response(opts = {}) ⇒ Object
- .restore_preferences(opts = {}) ⇒ Object
- .send(opts = {}) ⇒ Object
- .send_input_event(opts = {}) ⇒ Object
- .sensor_config(opts = {}) ⇒ Object
- .set_canned_messages(opts = {}) ⇒ Object
- .set_channel(opts = {}) ⇒ Object
- .set_config(opts = {}) ⇒ Object
- .set_favorite_node(opts = {}) ⇒ Object
- .set_fixed_position(opts = {}) ⇒ Object
- .set_ham_mode(opts = {}) ⇒ Object
- .set_ignored_node(opts = {}) ⇒ Object
- .set_module_config(opts = {}) ⇒ Object
- .set_owner(opts = {}) ⇒ Object
- .set_ringtone(opts = {}) ⇒ Object
- .set_scale(opts = {}) ⇒ Object
- .set_time(opts = {}) ⇒ Object
- .shutdown(opts = {}) ⇒ Object
- .store_ui_config(opts = {}) ⇒ Object
- .toggle_muted_node(opts = {}) ⇒ Object
-
.transport_type(opts = {}) ⇒ Object
Classify a handle returned by a transport's connect method.
Class Method Details
.add_contact(opts = {}) ⇒ Object
414 415 416 |
# File 'lib/meshtastic/admin.rb', line 414 public_class_method def self.add_contact(opts = {}) send(opts.merge(add_contact: opts[:contact])) end |
.authors ⇒ Object
446 447 448 |
# File 'lib/meshtastic/admin.rb', line 446 public_class_method def self. "AUTHOR(S):\n 0day Inc. <[email protected]>\n " end |
.backup_preferences(opts = {}) ⇒ Object
328 329 330 |
# File 'lib/meshtastic/admin.rb', line 328 public_class_method def self.backup_preferences(opts = {}) send(opts.merge(backup_preferences: opts[:location] || :FLASH)) end |
.begin_edit(opts = {}) ⇒ Object
406 407 408 |
# File 'lib/meshtastic/admin.rb', line 406 public_class_method def self.begin_edit(opts = {}) send(opts.merge(begin_edit_settings: true)) end |
.commit_edit(opts = {}) ⇒ Object
410 411 412 |
# File 'lib/meshtastic/admin.rb', line 410 public_class_method def self.commit_edit(opts = {}) send(opts.merge(commit_edit_settings: true)) end |
.decode(opts = {}) ⇒ Object
204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/meshtastic/admin.rb', line 204 public_class_method def self.decode(opts = {}) (opts) packet = opts[:packet] packet = packet.packet if packet.is_a?(Meshtastic::FromRadio) data = packet.is_a?(Meshtastic::MeshPacket) ? packet.decoded : packet raise ArgumentError, 'packet must contain decoded ADMIN_APP data' if opts.key?(:packet) && (!data.is_a?(Meshtastic::Data) || data.portnum != :ADMIN_APP) payload = data ? data.payload : opts[:payload] raise ArgumentError, 'payload bytes or a decoded packet are required' unless payload.is_a?(String) Meshtastic::AdminMessage.decode(payload) end |
.delete_file(opts = {}) ⇒ Object
320 321 322 |
# File 'lib/meshtastic/admin.rb', line 320 public_class_method def self.delete_file(opts = {}) send(opts.merge(delete_file_request: opts[:path])) end |
.encode(opts = {}) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/meshtastic/admin.rb', line 49 public_class_method def self.encode(opts = {}) (opts) original = opts[:message] || Meshtastic::AdminMessage.new raise ArgumentError, 'message must be an AdminMessage' unless original.is_a?(Meshtastic::AdminMessage) fields = opts.keys & PAYLOAD_FIELDS variants = (fields + [original.payload_variant]).compact.uniq raise ArgumentError, 'exactly one payload is required' unless variants.length == 1 unknown = opts.keys - SKIP - PAYLOAD_FIELDS - [:session_passkey] raise ArgumentError, "unknown admin options: #{unknown.join(', ')}" unless unknown.empty? = Meshtastic::AdminMessage.decode(original.to_proto) fields.each do |key| raise ArgumentError, "#{key} cannot be nil" if opts[key].nil? .public_send("#{key}=", opts[key]) end if opts.key?(:session_passkey) passkey = opts[:session_passkey] raise ArgumentError, 'session_passkey must contain exactly eight bytes' unless passkey.is_a?(String) && passkey.bytesize == 8 .session_passkey = passkey end end |
.enter_dfu(opts = {}) ⇒ Object
316 317 318 |
# File 'lib/meshtastic/admin.rb', line 316 public_class_method def self.enter_dfu(opts = {}) send(opts.merge(enter_dfu_mode_request: true)) end |
.exit_simulator(opts = {}) ⇒ Object
434 435 436 |
# File 'lib/meshtastic/admin.rb', line 434 public_class_method def self.exit_simulator(opts = {}) send(opts.merge(exit_simulator: true)) end |
.factory_reset_config(opts = {}) ⇒ Object
426 427 428 |
# File 'lib/meshtastic/admin.rb', line 426 public_class_method def self.factory_reset_config(opts = {}) send(opts.merge(factory_reset_config: opts[:value] || 1)) end |
.factory_reset_device(opts = {}) ⇒ Object
422 423 424 |
# File 'lib/meshtastic/admin.rb', line 422 public_class_method def self.factory_reset_device(opts = {}) send(opts.merge(factory_reset_device: opts[:value] || 1)) end |
.get_canned_messages(opts = {}) ⇒ Object
288 289 290 |
# File 'lib/meshtastic/admin.rb', line 288 public_class_method def self.(opts = {}) send(opts.merge(get_canned_message_module_messages_request: true)) end |
.get_channel(opts = {}) ⇒ Object
264 265 266 267 268 269 270 |
# File 'lib/meshtastic/admin.rb', line 264 public_class_method def self.get_channel(opts = {}) index = opts[:index] index = 0 if index.nil? raise ArgumentError, 'index must be an Integer from 0 through 7' unless index.is_a?(Integer) && index.between?(0, 7) send(opts.merge(get_channel_request: index + 1)) end |
.get_config(opts = {}) ⇒ Object
272 273 274 |
# File 'lib/meshtastic/admin.rb', line 272 public_class_method def self.get_config(opts = {}) send(opts.merge(get_config_request: opts[:config_type] || :DEVICE_CONFIG)) end |
.get_device_connection_status(opts = {}) ⇒ Object
308 309 310 |
# File 'lib/meshtastic/admin.rb', line 308 public_class_method def self.get_device_connection_status(opts = {}) send(opts.merge(get_device_connection_status_request: true)) end |
.get_device_metadata(opts = {}) ⇒ Object
296 297 298 |
# File 'lib/meshtastic/admin.rb', line 296 public_class_method def self.(opts = {}) send(opts.merge(get_device_metadata_request: true)) end |
.get_module_config(opts = {}) ⇒ Object
280 281 282 |
# File 'lib/meshtastic/admin.rb', line 280 public_class_method def self.get_module_config(opts = {}) send(opts.merge(get_module_config_request: opts[:module_config_type] || :MQTT_CONFIG)) end |
.get_node_remote_hardware_pins(opts = {}) ⇒ Object
312 313 314 |
# File 'lib/meshtastic/admin.rb', line 312 public_class_method def self.get_node_remote_hardware_pins(opts = {}) send(opts.merge(get_node_remote_hardware_pins_request: true)) end |
.get_owner(opts = {}) ⇒ Object
256 257 258 |
# File 'lib/meshtastic/admin.rb', line 256 public_class_method def self.get_owner(opts = {}) send(opts.merge(get_owner_request: true)) end |
.get_ringtone(opts = {}) ⇒ Object
300 301 302 |
# File 'lib/meshtastic/admin.rb', line 300 public_class_method def self.get_ringtone(opts = {}) send(opts.merge(get_ringtone_request: true)) end |
.get_ui_config(opts = {}) ⇒ Object
386 387 388 |
# File 'lib/meshtastic/admin.rb', line 386 public_class_method def self.get_ui_config(opts = {}) send(opts.merge(get_ui_config_request: true)) end |
.help ⇒ Object
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 |
# File 'lib/meshtastic/admin.rb', line 450 public_class_method def self.help puts "USAGE: # Classify the actual connected transport handle. #{self}.transport_type( transport_obj: 'required - handle from Serial.connect, Bluetooth.connect, TCP.connect or MQTT.connect' ) # Returns :serial, :bluetooth, :tcp or :mqtt; TCP includes serial framing keys. # Nil, unknown and ambiguous handles are rejected. Old transport option keys are rejected. # All send wrappers below require transport_obj and accept the shared send options. # Encode exactly one AdminMessage payload without modifying the caller. #{self}.encode( message: 'optional - existing AdminMessage to copy instead of a new one', session_passkey: 'optional - bytes from a prior get_*_response to authorize sets' ) # Send an AdminMessage on ADMIN_APP over a connected transport. #{self}.send( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client', to: 'optional - unicast node integer or !eighthex; defaults to connected my_node_num; required for MQTT', from: 'optional - sender number; radio default zero denotes the local PhoneAPI client', channel: 'optional - routing channel index (default zero)', want_ack: 'optional - request routing acknowledgment, distinct from an admin reply', hop_limit: 'optional - maximum radio hop count', psks: 'optional - MQTT channel key map; not public-key admin authorization', pki_encrypted: 'optional - enable device-owned PKI on serial BLE or TCP; unsupported over MQTT', public_key: 'optional - recipient public-key bytes for radio PKI', last_packet_id: 'optional - previous packet number used by transport packet generation', want_response: 'optional - defaults true for get requests and false for state changes', auto_session: 'optional - acquire a session for remote writes unless a passkey is supplied (default true)', refresh_session: 'optional - discard cached session for this automatic acquisition (default false)', timeout: 'optional - positive finite receive deadline in seconds for session acquisition (default ten)' ) # Send admin data and synchronously await correlated readback. #{self}.request( request_id: 'optional - packet ID from 2 through 0xffffffff; generated when omitted; accepts send options', wait: 'optional - false returns only request_id and submission result; true waits for reply (default true)', timeout: 'optional - positive finite total response budget in seconds including session acquisition (default ten)' ) # Decode protobuf bytes or an incoming admin packet. #{self}.decode( payload: 'optional - serialized AdminMessage bytes when packet is omitted', packet: 'optional - FromRadio MeshPacket or Data containing decoded ADMIN_APP bytes' ) # Extract a matching response and its session passkey. #{self}.response( packet: 'required - incoming FromRadio or MeshPacket protobuf', request_id: 'optional - require this Data.request_id to match the outgoing packet ID', from: 'optional - require this numeric responding node; mismatches return nil' ) # Request legacy ESP32 OTA reboot; deprecated firmware operation. #{self}.reboot_ota( seconds: 'optional - legacy reboot delay, negative cancels (default five); use ota_request on current firmware' ) # Send the current OTA loader request protobuf. #{self}.ota_request( event: 'required - AdminMessage::OTAEvent containing mode and firmware hash; see Admin::Firmware' ) # Reboot the node after a delay. #{self}.reboot( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client', seconds: 'optional - delay before reboot in seconds (default: 5)' ) # Shut down the node after a delay. #{self}.shutdown( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client', seconds: 'optional - delay before shutdown in seconds (default: 5)' ) # Set the node owner User protobuf. #{self}.set_owner( owner: 'optional - Meshtastic::User protobuf to send as set_owner', long_name: 'optional - owner long name when owner is omitted', short_name: 'optional - owner short name when owner is omitted' ) # Request the node owner User protobuf. #{self}.get_owner( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Write a Channel protobuf to the node. #{self}.set_channel( channel_settings: 'optional - Meshtastic::Channel protobuf to write', channel_pb: 'optional - Channel protobuf alias used as set_channel' ) # Request a channel by index. #{self}.get_channel( index: 'optional - zero-based channel index 0 through 7; wire conversion happens here (default zero)' ) # Request a radio Config section. #{self}.get_config( config_type: 'optional - AdminMessage::ConfigType such as :LORA_CONFIG' ) # Write a Config protobuf to the node. #{self}.set_config( config: 'required - Meshtastic::Config protobuf to write' ) # Request a ModuleConfig section. #{self}.get_module_config( module_config_type: 'optional - ModuleConfigType such as :MQTT_CONFIG' ) # Write a ModuleConfig protobuf to the node. #{self}.set_module_config( module_config: 'required - Meshtastic::ModuleConfig protobuf to write' ) # Request canned-message module strings. #{self}.get_canned_messages( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Set canned-message module strings. #{self}.set_canned_messages( messages: 'required - pipe-separated canned message text; empty string clears it' ) # Request DeviceMetadata (firmware version and hardware). #{self}.get_device_metadata( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Request the RTTTL ringtone string. #{self}.get_ringtone( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Set the RTTTL ringtone string. #{self}.set_ringtone( ringtone: 'required - RTTTL ringtone text to store on the node' ) # Request DeviceConnectionStatus. #{self}.get_device_connection_status( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Request remote-hardware pin definitions. #{self}.get_node_remote_hardware_pins( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Ask the node to enter DFU / UF2 mode. #{self}.enter_dfu( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Delete a file on the node filesystem. #{self}.delete_file( path: 'required - filesystem path on the node to delete' ) # Set the NAU7802 scale calibration value. #{self}.set_scale( scale: 'required - integer scale factor for the NAU7802 module' ) # Backup preferences to flash or SD. #{self}.backup_preferences( location: 'optional - :FLASH or :SD backup location (default: :FLASH)' ) # Restore preferences from flash or SD. #{self}.restore_preferences( location: 'optional - :FLASH or :SD backup location (default: :FLASH)' ) # Remove a preferences backup from flash or SD. #{self}.remove_backup_preferences( location: 'optional - :FLASH or :SD backup location (default: :FLASH)' ) # Inject a device-UI input event. #{self}.send_input_event( event: 'optional - AdminMessage::InputEvent protobuf to send', event_code: 'optional - input event code when event is omitted', kb_char: 'optional - keyboard character code when event is omitted', touch_x: 'optional - touch X coordinate when event is omitted', touch_y: 'optional - touch Y coordinate when event is omitted' ) # Enable ham-radio identity parameters. #{self}.set_ham_mode( ham: 'optional - HamParameters protobuf to send', call_sign: 'optional - amateur callsign when ham is omitted', tx_power: 'optional - transmit power when ham is omitted', frequency: 'optional - frequency in MHz when ham is omitted', short_name: 'optional - short name when ham is omitted', long_name: 'optional - long name when ham is omitted' ) # Remove a node from the local nodedb by number. #{self}.remove_by_nodenum( node_num: 'required - node number to remove from the nodedb' ) # Mark a node as a favorite. #{self}.set_favorite_node( node_num: 'required - node number to mark as favorite' ) # Clear favorite status for a node. #{self}.remove_favorite_node( node_num: 'required - node number to unfavorite' ) # Set a fixed GPS position on the node. #{self}.set_fixed_position( position: 'optional - Meshtastic::Position protobuf to store', lat: 'optional - latitude in decimal degrees when position is omitted', lon: 'optional - longitude in decimal degrees when position is omitted', altitude: 'optional - altitude in meters when position is omitted' ) # Clear the fixed GPS position on the node. #{self}.remove_fixed_position( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Set node wall-clock time. #{self}.set_time( time: 'required - unix timestamp to set on the node' ) # Request DeviceUIConfig. #{self}.get_ui_config( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Store DeviceUIConfig on the node. #{self}.store_ui_config( ui_config: 'required - Meshtastic::DeviceUIConfig protobuf to store' ) # Ignore a node number. #{self}.set_ignored_node( node_num: 'required - node number to ignore' ) # Stop ignoring a node number. #{self}.remove_ignored_node( node_num: 'required - node number to stop ignoring' ) # Toggle mute for a node number. #{self}.toggle_muted_node( node_num: 'required - node number whose mute flag should toggle' ) # Open a settings edit transaction. #{self}.begin_edit( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Commit a settings edit transaction. #{self}.commit_edit( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Add a SharedContact to the node. #{self}.add_contact( contact: 'required - Meshtastic::SharedContact protobuf to add' ) # Send a KeyVerificationAdmin protobuf. #{self}.key_verification( key_verification: 'required - KeyVerificationAdmin protobuf to send' ) # Factory-reset device state including BLE bonds. #{self}.factory_reset_device( value: 'optional - int32 factory_reset_device field (default: 1)' ) # Factory-reset configuration only. #{self}.factory_reset_config( value: 'optional - int32 factory_reset_config field (default: 1)' ) # Clear the node database. #{self}.nodedb_reset( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client', preserve_favorites: 'optional - retain favorite nodes (default true); some firmware roles always preserve favorites' ) # Exit the firmware simulator if running. #{self}.exit_simulator( transport_obj: 'required - actual connected Serial, Bluetooth, TCP handle or MQTT client' ) # Write a SensorConfig protobuf. #{self}.sensor_config( sensor_config: 'required - Meshtastic::SensorConfig protobuf to write' ) # Send lockdown authentication material. #{self}.lockdown_auth( lockdown_auth: 'required - Meshtastic::LockdownAuth protobuf to send' ) # Print the AUTHOR(S) string for this module. #{self}.authors " end |
.key_verification(opts = {}) ⇒ Object
418 419 420 |
# File 'lib/meshtastic/admin.rb', line 418 public_class_method def self.key_verification(opts = {}) send(opts.merge(key_verification: opts[:key_verification])) end |
.lockdown_auth(opts = {}) ⇒ Object
442 443 444 |
# File 'lib/meshtastic/admin.rb', line 442 public_class_method def self.lockdown_auth(opts = {}) send(opts.merge(lockdown_auth: opts[:lockdown_auth])) end |
.nodedb_reset(opts = {}) ⇒ Object
430 431 432 |
# File 'lib/meshtastic/admin.rb', line 430 public_class_method def self.nodedb_reset(opts = {}) send(opts.merge(nodedb_reset: opts.fetch(:preserve_favorites, true))) end |
.ota_request(opts = {}) ⇒ Object
247 248 249 |
# File 'lib/meshtastic/admin.rb', line 247 public_class_method def self.ota_request(opts = {}) send(opts.merge(ota_request: opts[:event])) end |
.reboot(opts = {}) ⇒ Object
235 236 237 |
# File 'lib/meshtastic/admin.rb', line 235 public_class_method def self.reboot(opts = {}) send(opts.merge(reboot_seconds: opts[:seconds] || 5)) end |
.reboot_ota(opts = {}) ⇒ Object
243 244 245 |
# File 'lib/meshtastic/admin.rb', line 243 public_class_method def self.reboot_ota(opts = {}) send(opts.merge(reboot_ota_seconds: opts[:seconds] || 5)) end |
.remove_backup_preferences(opts = {}) ⇒ Object
336 337 338 |
# File 'lib/meshtastic/admin.rb', line 336 public_class_method def self.remove_backup_preferences(opts = {}) send(opts.merge(remove_backup_preferences: opts[:location] || :FLASH)) end |
.remove_by_nodenum(opts = {}) ⇒ Object
361 362 363 |
# File 'lib/meshtastic/admin.rb', line 361 public_class_method def self.remove_by_nodenum(opts = {}) send(opts.merge(remove_by_nodenum: opts[:node_num])) end |
.remove_favorite_node(opts = {}) ⇒ Object
369 370 371 |
# File 'lib/meshtastic/admin.rb', line 369 public_class_method def self.remove_favorite_node(opts = {}) send(opts.merge(remove_favorite_node: opts[:node_num])) end |
.remove_fixed_position(opts = {}) ⇒ Object
378 379 380 |
# File 'lib/meshtastic/admin.rb', line 378 public_class_method def self.remove_fixed_position(opts = {}) send(opts.merge(remove_fixed_position: true)) end |
.remove_ignored_node(opts = {}) ⇒ Object
398 399 400 |
# File 'lib/meshtastic/admin.rb', line 398 public_class_method def self.remove_ignored_node(opts = {}) send(opts.merge(remove_ignored_node: opts[:node_num])) end |
.request(opts = {}) ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/meshtastic/admin.rb', line 100 public_class_method def self.request(opts = {}) type = transport_type(opts) request_id = opts.fetch(:request_id) { Random.rand(2..0xffffffff) } raise ArgumentError, 'request_id must be an Integer from 2 through 0xffffffff' unless request_id.is_a?(Integer) && request_id.between?(2, 0xffffffff) = opts.except(:request_id, :wait) return { request_id: request_id, result: send(.merge(last_packet_id: request_id - 1)) } unless opts.fetch(:wait, true) connection = [:transport_obj] unless type == :mqtt queue = connection && connection[:from_radio_queue] raise ArgumentError, 'synchronous Admin requires a connected radio receive queue' unless queue timeout = opts.fetch(:timeout, 10) raise ArgumentError, 'timeout must be a positive finite number' unless timeout.is_a?(Numeric) && timeout.positive? && timeout.finite? lock = connection[:admin_request_lock] ||= Monitor.new acquired = lock.try_enter raise IOError, 'a synchronous Admin request is already active on this handle' unless acquired deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout = encode() target = .fetch(:to, connection[:my_node_num]) target = target.delete_prefix('!').to_i(16) if target.is_a?(String) && target.match?(/\A![0-9a-fA-F]{8}\z/) result = send(.merge(last_packet_id: request_id - 1, want_response: true, want_ack: true, timeout: timeout)) variant = .payload_variant.to_s expected = variant.match?(/\Aget_.*_request\z/) ? variant.sub(/_request\z/, '_response').to_sym : :routing reply = await_response(connection: connection, queue: queue, deadline: deadline, request_id: request_id, target: target, variant: expected) if reply[:session_passkey]&.bytesize == 8 sessions = connection[:admin_sessions] ||= {} sessions[target] = { key: reply[:session_passkey], expires_at: deadline - timeout + 150 } end reply.merge(result: result) rescue RoutingError => e connection[:admin_sessions]&.delete(target) if connection && e.reason == :ADMIN_BAD_SESSION_KEY raise ensure lock.exit if acquired end |
.response(opts = {}) ⇒ Object
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/meshtastic/admin.rb', line 217 public_class_method def self.response(opts = {}) (opts) packet = opts[:packet] packet = packet.packet if packet.is_a?(Meshtastic::FromRadio) return nil unless packet.is_a?(Meshtastic::MeshPacket) && packet.decoded&.portnum == :ADMIN_APP return nil if opts.key?(:request_id) && packet.decoded.request_id != opts[:request_id] return nil if opts.key?(:from) && packet.from != opts[:from] = decode(packet: packet) variant = .payload_variant return nil unless variant.to_s.end_with?('_response') { message: , variant: variant, value: .public_send(variant), session_passkey: .session_passkey, request_id: packet.decoded.request_id, from: packet.from } end |
.restore_preferences(opts = {}) ⇒ Object
332 333 334 |
# File 'lib/meshtastic/admin.rb', line 332 public_class_method def self.restore_preferences(opts = {}) send(opts.merge(restore_preferences: opts[:location] || :FLASH)) end |
.send(opts = {}) ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/meshtastic/admin.rb', line 76 public_class_method def self.send(opts = {}) type = transport_type(opts) = encode(opts) connection = opts[:transport_obj] unless type == :mqtt destination = opts[:to] || connection&.dig(:my_node_num) destination = destination.delete_prefix('!').to_i(16) if destination.is_a?(String) && destination.match?(/\A![0-9a-fA-F]{8}\z/) raise ArgumentError, 'an explicit unicast destination or connected my_node_num is required' unless destination.is_a?(Integer) && destination.between?(1, 0xfffffffe) if opts.fetch(:auto_session, true) && .session_passkey.empty? && destination != connection&.dig(:my_node_num) && !.payload_variant.to_s.match?(/\Aget_.*_(request|response)\z/) .session_passkey = acquire_session(opts.merge(connection: connection, target: destination)) end want_response = opts.fetch(:want_response) { .payload_variant.to_s.match?(/\Aget_.*_request\z/) } data = Meshtastic::Data.new( portnum: :ADMIN_APP, payload: .to_proto, want_response: want_response ) delivery = opts.except(:transport_obj).merge(data: data, port_num: Meshtastic::PortNum::ADMIN_APP, to: destination) delivery[:"#{type}_obj"] = opts[:transport_obj] delivery[:from] = 0 if connection && !opts.key?(:from) Meshtastic.deliver_data(delivery) end |
.send_input_event(opts = {}) ⇒ Object
340 341 342 343 344 345 346 347 348 |
# File 'lib/meshtastic/admin.rb', line 340 public_class_method def self.send_input_event(opts = {}) event = opts[:event] || Meshtastic::AdminMessage::InputEvent.new( event_code: opts[:event_code].to_i, kb_char: opts[:kb_char].to_i, touch_x: opts[:touch_x].to_i, touch_y: opts[:touch_y].to_i ) send(opts.merge(send_input_event: event)) end |
.sensor_config(opts = {}) ⇒ Object
438 439 440 |
# File 'lib/meshtastic/admin.rb', line 438 public_class_method def self.sensor_config(opts = {}) send(opts.merge(sensor_config: opts[:sensor_config])) end |
.set_canned_messages(opts = {}) ⇒ Object
292 293 294 |
# File 'lib/meshtastic/admin.rb', line 292 public_class_method def self.(opts = {}) send(opts.merge(set_canned_message_module_messages: opts[:messages])) end |
.set_channel(opts = {}) ⇒ Object
260 261 262 |
# File 'lib/meshtastic/admin.rb', line 260 public_class_method def self.set_channel(opts = {}) send(opts.merge(set_channel: opts[:channel_settings] || opts[:channel_pb])) end |
.set_config(opts = {}) ⇒ Object
276 277 278 |
# File 'lib/meshtastic/admin.rb', line 276 public_class_method def self.set_config(opts = {}) send(opts.merge(set_config: opts[:config])) end |
.set_favorite_node(opts = {}) ⇒ Object
365 366 367 |
# File 'lib/meshtastic/admin.rb', line 365 public_class_method def self.set_favorite_node(opts = {}) send(opts.merge(set_favorite_node: opts[:node_num])) end |
.set_fixed_position(opts = {}) ⇒ Object
373 374 375 376 |
# File 'lib/meshtastic/admin.rb', line 373 public_class_method def self.set_fixed_position(opts = {}) position = opts[:position] || Meshtastic::Position.build(lat: opts[:lat], lon: opts[:lon], altitude: opts[:altitude]) send(opts.merge(set_fixed_position: position)) end |
.set_ham_mode(opts = {}) ⇒ Object
350 351 352 353 354 355 356 357 358 359 |
# File 'lib/meshtastic/admin.rb', line 350 public_class_method def self.set_ham_mode(opts = {}) ham = opts[:ham] || Meshtastic::HamParameters.new( call_sign: opts[:call_sign].to_s, tx_power: opts[:tx_power].to_i, frequency: opts[:frequency].to_f, short_name: opts[:short_name].to_s, long_name: opts[:long_name].to_s ) send(opts.merge(set_ham_mode: ham)) end |
.set_ignored_node(opts = {}) ⇒ Object
394 395 396 |
# File 'lib/meshtastic/admin.rb', line 394 public_class_method def self.set_ignored_node(opts = {}) send(opts.merge(set_ignored_node: opts[:node_num])) end |
.set_module_config(opts = {}) ⇒ Object
284 285 286 |
# File 'lib/meshtastic/admin.rb', line 284 public_class_method def self.set_module_config(opts = {}) send(opts.merge(set_module_config: opts[:module_config])) end |
.set_owner(opts = {}) ⇒ Object
251 252 253 254 |
# File 'lib/meshtastic/admin.rb', line 251 public_class_method def self.set_owner(opts = {}) user = opts[:owner] || Meshtastic::User.new(long_name: opts[:long_name], short_name: opts[:short_name]) send(opts.merge(set_owner: user)) end |
.set_ringtone(opts = {}) ⇒ Object
304 305 306 |
# File 'lib/meshtastic/admin.rb', line 304 public_class_method def self.set_ringtone(opts = {}) send(opts.merge(set_ringtone_message: opts[:ringtone])) end |
.set_scale(opts = {}) ⇒ Object
324 325 326 |
# File 'lib/meshtastic/admin.rb', line 324 public_class_method def self.set_scale(opts = {}) send(opts.merge(set_scale: opts[:scale])) end |
.set_time(opts = {}) ⇒ Object
382 383 384 |
# File 'lib/meshtastic/admin.rb', line 382 public_class_method def self.set_time(opts = {}) send(opts.merge(set_time_only: opts[:time])) end |
.shutdown(opts = {}) ⇒ Object
239 240 241 |
# File 'lib/meshtastic/admin.rb', line 239 public_class_method def self.shutdown(opts = {}) send(opts.merge(shutdown_seconds: opts[:seconds] || 5)) end |
.store_ui_config(opts = {}) ⇒ Object
390 391 392 |
# File 'lib/meshtastic/admin.rb', line 390 public_class_method def self.store_ui_config(opts = {}) send(opts.merge(store_ui_config: opts[:ui_config])) end |
.toggle_muted_node(opts = {}) ⇒ Object
402 403 404 |
# File 'lib/meshtastic/admin.rb', line 402 public_class_method def self.toggle_muted_node(opts = {}) send(opts.merge(toggle_muted_node: opts[:node_num])) end |
.transport_type(opts = {}) ⇒ Object
Classify a handle returned by a transport's connect method.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/meshtastic/admin.rb', line 32 public_class_method def self.transport_type(opts = {}) (opts) transport = opts[:transport_obj] return :mqtt if transport.is_a?(MQTTClient) raise ArgumentError, 'transport_obj has ambiguous transport handle keys' if transport.is_a?(Hash) && transport.key?(:bluetooth_conn) && (transport.key?(:serial_conn) || transport.key?(:tcp_socket)) if transport.is_a?(Hash) && transport.key?(:tcp_socket) raise ArgumentError, 'transport_obj TCP handle requires tcp_socket and serial_conn' unless transport[:tcp_socket] && transport[:serial_conn] return :tcp end return :bluetooth if transport.is_a?(Hash) && transport[:bluetooth_conn] return :serial if transport.is_a?(Hash) && transport[:serial_conn] raise ArgumentError, 'transport_obj must be a connected Serial, Bluetooth, TCP handle or MQTT client' end |