mirror of
https://github.com/meshtastic/python.git
synced 2025-12-26 09:27:52 -05:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69bb8bcca2 | ||
|
|
bb2ea17371 | ||
|
|
b51af8a070 | ||
|
|
aede26694c | ||
|
|
8e1010e9f2 | ||
|
|
ce2d9f5728 | ||
|
|
9879e9f2df | ||
|
|
e79faf93d0 | ||
|
|
181c04716a | ||
|
|
c7d981ec35 | ||
|
|
75fe7622a4 | ||
|
|
5dc800f9a3 | ||
|
|
c7d3f9f787 | ||
|
|
c70d36d2cd | ||
|
|
f239c23d9a | ||
|
|
ac5d729cdf | ||
|
|
047f43534f | ||
|
|
c26e030f1f |
24
.github/workflows/update_protobufs.yml
vendored
Normal file
24
.github/workflows/update_protobufs.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
name: "Update protobufs"
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
update-protobufs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Update Submodule
|
||||
run: |
|
||||
git pull --recurse-submodules
|
||||
git submodule update --remote --recursive
|
||||
- name: Commit update
|
||||
run: |
|
||||
git config --global user.name 'github-actions'
|
||||
git config --global user.email 'bot@noreply.github.com'
|
||||
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
|
||||
git add proto
|
||||
git commit -m "Update protobuf submodule" && git push || echo "No changes to commit"
|
||||
@@ -23,7 +23,7 @@ ignore-patterns=mqtt_pb2.py,channel_pb2.py,environmental_measurement_pb2.py,admi
|
||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||
# --disable=W"
|
||||
#
|
||||
disable=invalid-name,fixme,logging-fstring-interpolation,too-many-statements,too-many-branches,too-many-locals,no-member,f-string-without-interpolation,protected-access,no-self-use,pointless-string-statement,too-few-public-methods,consider-using-f-string,broad-except,no-else-return,unused-argument,global-statement,global-variable-not-assigned,too-many-boolean-expressions,no-else-raise,bare-except
|
||||
disable=invalid-name,fixme,logging-fstring-interpolation,too-many-statements,too-many-branches,too-many-locals,no-member,f-string-without-interpolation,protected-access,no-self-use,pointless-string-statement,too-few-public-methods,consider-using-f-string,broad-except,no-else-return,unused-argument,global-statement,global-variable-not-assigned,too-many-boolean-expressions,no-else-raise,bare-except,c-extension-no-member
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
1118
docs/meshtastic/admin_pb2.html
Normal file
1118
docs/meshtastic/admin_pb2.html
Normal file
File diff suppressed because it is too large
Load Diff
707
docs/meshtastic/apponly_pb2.html
Normal file
707
docs/meshtastic/apponly_pb2.html
Normal file
@@ -0,0 +1,707 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.apponly_pb2 API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.apponly_pb2</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: apponly.proto
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from . import channel_pb2 as channel__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='apponly.proto',
|
||||
package='',
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\023com.geeksville.meshB\rAppOnlyProtosH\003Z!github.com/meshtastic/gomeshproto',
|
||||
serialized_pb=b'\n\rapponly.proto\x1a\rchannel.proto\"0\n\nChannelSet\x12\"\n\x08settings\x18\x01 \x03(\x0b\x32\x10.ChannelSettingsBI\n\x13\x63om.geeksville.meshB\rAppOnlyProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
|
||||
,
|
||||
dependencies=[channel__pb2.DESCRIPTOR,])
|
||||
|
||||
|
||||
|
||||
|
||||
_CHANNELSET = _descriptor.Descriptor(
|
||||
name='ChannelSet',
|
||||
full_name='ChannelSet',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='settings', full_name='ChannelSet.settings', index=0,
|
||||
number=1, type=11, cpp_type=10, label=3,
|
||||
has_default_value=False, default_value=[],
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=32,
|
||||
serialized_end=80,
|
||||
)
|
||||
|
||||
_CHANNELSET.fields_by_name['settings'].message_type = channel__pb2._CHANNELSETTINGS
|
||||
DESCRIPTOR.message_types_by_name['ChannelSet'] = _CHANNELSET
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
ChannelSet = _reflection.GeneratedProtocolMessageType('ChannelSet', (_message.Message,), {
|
||||
'DESCRIPTOR' : _CHANNELSET,
|
||||
'__module__' : 'apponly_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ChannelSet)
|
||||
})
|
||||
_sym_db.RegisterMessage(ChannelSet)
|
||||
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet"><code class="flex name class">
|
||||
<span>class <span class="ident">ChannelSet</span></span>
|
||||
<span>(</span><span>**kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Abstract base class for protocol messages.</p>
|
||||
<p>Protocol message classes are almost always generated by the protocol
|
||||
compiler.
|
||||
These generated types subclass Message and implement the methods
|
||||
shown below.</p></div>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>google.protobuf.message.Message</li>
|
||||
</ul>
|
||||
<h3>Class variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.SETTINGS_FIELD_NUMBER"><code class="name">var <span class="ident">SETTINGS_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Static methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.FromString"><code class="name flex">
|
||||
<span>def <span class="ident">FromString</span></span>(<span>s)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def FromString(s):
|
||||
message = cls()
|
||||
message.MergeFromString(s)
|
||||
return message</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.RegisterExtension"><code class="name flex">
|
||||
<span>def <span class="ident">RegisterExtension</span></span>(<span>extension_handle)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def RegisterExtension(extension_handle):
|
||||
extension_handle.containing_type = cls.DESCRIPTOR
|
||||
# TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
|
||||
# pylint: disable=protected-access
|
||||
cls.DESCRIPTOR.file.pool._AddExtensionDescriptor(extension_handle)
|
||||
_AttachFieldHelpers(cls, extension_handle)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Instance variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.settings"><code class="name">var <span class="ident">settings</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for settings.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
field_value = self._fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
|
||||
# Atomically check if another thread has preempted us and, if not, swap
|
||||
# in the new object we just created. If someone has preempted us, we
|
||||
# take that object and discard ours.
|
||||
# WARNING: We are relying on setdefault() being atomic. This is true
|
||||
# in CPython but we haven't investigated others. This warning appears
|
||||
# in several other locations in this file.
|
||||
field_value = self._fields.setdefault(field, field_value)
|
||||
return field_value</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.ByteSize"><code class="name flex">
|
||||
<span>def <span class="ident">ByteSize</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ByteSize(self):
|
||||
if not self._cached_byte_size_dirty:
|
||||
return self._cached_byte_size
|
||||
|
||||
size = 0
|
||||
descriptor = self.DESCRIPTOR
|
||||
if descriptor.GetOptions().map_entry:
|
||||
# Fields of map entry should always be serialized.
|
||||
size = descriptor.fields_by_name['key']._sizer(self.key)
|
||||
size += descriptor.fields_by_name['value']._sizer(self.value)
|
||||
else:
|
||||
for field_descriptor, field_value in self.ListFields():
|
||||
size += field_descriptor._sizer(field_value)
|
||||
for tag_bytes, value_bytes in self._unknown_fields:
|
||||
size += len(tag_bytes) + len(value_bytes)
|
||||
|
||||
self._cached_byte_size = size
|
||||
self._cached_byte_size_dirty = False
|
||||
self._listener_for_children.dirty = False
|
||||
return size</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.Clear"><code class="name flex">
|
||||
<span>def <span class="ident">Clear</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _Clear(self):
|
||||
# Clear fields.
|
||||
self._fields = {}
|
||||
self._unknown_fields = ()
|
||||
# pylint: disable=protected-access
|
||||
if self._unknown_field_set is not None:
|
||||
self._unknown_field_set._clear()
|
||||
self._unknown_field_set = None
|
||||
|
||||
self._oneofs = {}
|
||||
self._Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.ClearField"><code class="name flex">
|
||||
<span>def <span class="ident">ClearField</span></span>(<span>self, field_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ClearField(self, field_name):
|
||||
try:
|
||||
field = message_descriptor.fields_by_name[field_name]
|
||||
except KeyError:
|
||||
try:
|
||||
field = message_descriptor.oneofs_by_name[field_name]
|
||||
if field in self._oneofs:
|
||||
field = self._oneofs[field]
|
||||
else:
|
||||
return
|
||||
except KeyError:
|
||||
raise ValueError('Protocol message %s has no "%s" field.' %
|
||||
(message_descriptor.name, field_name))
|
||||
|
||||
if field in self._fields:
|
||||
# To match the C++ implementation, we need to invalidate iterators
|
||||
# for map fields when ClearField() happens.
|
||||
if hasattr(self._fields[field], 'InvalidateIterators'):
|
||||
self._fields[field].InvalidateIterators()
|
||||
|
||||
# Note: If the field is a sub-message, its listener will still point
|
||||
# at us. That's fine, because the worst than can happen is that it
|
||||
# will call _Modified() and invalidate our byte size. Big deal.
|
||||
del self._fields[field]
|
||||
|
||||
if self._oneofs.get(field.containing_oneof, None) is field:
|
||||
del self._oneofs[field.containing_oneof]
|
||||
|
||||
# Always call _Modified() -- even if nothing was changed, this is
|
||||
# a mutating method, and thus calling it should cause the field to become
|
||||
# present in the parent message.
|
||||
self._Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.DiscardUnknownFields"><code class="name flex">
|
||||
<span>def <span class="ident">DiscardUnknownFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _DiscardUnknownFields(self):
|
||||
self._unknown_fields = []
|
||||
self._unknown_field_set = None # pylint: disable=protected-access
|
||||
for field, value in self.ListFields():
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if _IsMapField(field):
|
||||
if _IsMessageMapField(field):
|
||||
for key in value:
|
||||
value[key].DiscardUnknownFields()
|
||||
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
for sub_message in value:
|
||||
sub_message.DiscardUnknownFields()
|
||||
else:
|
||||
value.DiscardUnknownFields()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.FindInitializationErrors"><code class="name flex">
|
||||
<span>def <span class="ident">FindInitializationErrors</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Finds required fields which are not initialized.</p>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>A list of strings.
|
||||
Each string is a path to an uninitialized field from
|
||||
the top-level message, e.g. "foo.bar[5].baz".</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def FindInitializationErrors(self):
|
||||
"""Finds required fields which are not initialized.
|
||||
|
||||
Returns:
|
||||
A list of strings. Each string is a path to an uninitialized field from
|
||||
the top-level message, e.g. "foo.bar[5].baz".
|
||||
"""
|
||||
|
||||
errors = [] # simplify things
|
||||
|
||||
for field in required_fields:
|
||||
if not self.HasField(field.name):
|
||||
errors.append(field.name)
|
||||
|
||||
for field, value in self.ListFields():
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if field.is_extension:
|
||||
name = '(%s)' % field.full_name
|
||||
else:
|
||||
name = field.name
|
||||
|
||||
if _IsMapField(field):
|
||||
if _IsMessageMapField(field):
|
||||
for key in value:
|
||||
element = value[key]
|
||||
prefix = '%s[%s].' % (name, key)
|
||||
sub_errors = element.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
else:
|
||||
# ScalarMaps can't have any initialization errors.
|
||||
pass
|
||||
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
for i in range(len(value)):
|
||||
element = value[i]
|
||||
prefix = '%s[%d].' % (name, i)
|
||||
sub_errors = element.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
else:
|
||||
prefix = name + '.'
|
||||
sub_errors = value.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
|
||||
return errors</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.HasField"><code class="name flex">
|
||||
<span>def <span class="ident">HasField</span></span>(<span>self, field_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def HasField(self, field_name):
|
||||
try:
|
||||
field = hassable_fields[field_name]
|
||||
except KeyError:
|
||||
raise ValueError(error_msg % (message_descriptor.full_name, field_name))
|
||||
|
||||
if isinstance(field, descriptor_mod.OneofDescriptor):
|
||||
try:
|
||||
return HasField(self, self._oneofs[field].name)
|
||||
except KeyError:
|
||||
return False
|
||||
else:
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
value = self._fields.get(field)
|
||||
return value is not None and value._is_present_in_parent
|
||||
else:
|
||||
return field in self._fields</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.IsInitialized"><code class="name flex">
|
||||
<span>def <span class="ident">IsInitialized</span></span>(<span>self, errors=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Checks if all required fields of a message are set.</p>
|
||||
<h2 id="args">Args</h2>
|
||||
<dl>
|
||||
<dt><strong><code>errors</code></strong></dt>
|
||||
<dd>A list which, if provided, will be populated with the field
|
||||
paths of all missing required fields.</dd>
|
||||
</dl>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>True iff the specified message has all required fields set.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def IsInitialized(self, errors=None):
|
||||
"""Checks if all required fields of a message are set.
|
||||
|
||||
Args:
|
||||
errors: A list which, if provided, will be populated with the field
|
||||
paths of all missing required fields.
|
||||
|
||||
Returns:
|
||||
True iff the specified message has all required fields set.
|
||||
"""
|
||||
|
||||
# Performance is critical so we avoid HasField() and ListFields().
|
||||
|
||||
for field in required_fields:
|
||||
if (field not in self._fields or
|
||||
(field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
|
||||
not self._fields[field]._is_present_in_parent)):
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
|
||||
for field, value in list(self._fields.items()): # dict can change size!
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
if (field.message_type.has_options and
|
||||
field.message_type.GetOptions().map_entry):
|
||||
continue
|
||||
for element in value:
|
||||
if not element.IsInitialized():
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
elif value._is_present_in_parent and not value.IsInitialized():
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
|
||||
return True</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.ListFields"><code class="name flex">
|
||||
<span>def <span class="ident">ListFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ListFields(self):
|
||||
all_fields = [item for item in self._fields.items() if _IsPresent(item)]
|
||||
all_fields.sort(key = lambda item: item[0].number)
|
||||
return all_fields</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.MergeFrom"><code class="name flex">
|
||||
<span>def <span class="ident">MergeFrom</span></span>(<span>self, msg)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def MergeFrom(self, msg):
|
||||
if not isinstance(msg, cls):
|
||||
raise TypeError(
|
||||
'Parameter to MergeFrom() must be instance of same class: '
|
||||
'expected %s got %s.' % (_FullyQualifiedClassName(cls),
|
||||
_FullyQualifiedClassName(msg.__class__)))
|
||||
|
||||
assert msg is not self
|
||||
self._Modified()
|
||||
|
||||
fields = self._fields
|
||||
|
||||
for field, value in msg._fields.items():
|
||||
if field.label == LABEL_REPEATED:
|
||||
field_value = fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
fields[field] = field_value
|
||||
field_value.MergeFrom(value)
|
||||
elif field.cpp_type == CPPTYPE_MESSAGE:
|
||||
if value._is_present_in_parent:
|
||||
field_value = fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
fields[field] = field_value
|
||||
field_value.MergeFrom(value)
|
||||
else:
|
||||
self._fields[field] = value
|
||||
if field.containing_oneof:
|
||||
self._UpdateOneofState(field)
|
||||
|
||||
if msg._unknown_fields:
|
||||
if not self._unknown_fields:
|
||||
self._unknown_fields = []
|
||||
self._unknown_fields.extend(msg._unknown_fields)
|
||||
# pylint: disable=protected-access
|
||||
if self._unknown_field_set is None:
|
||||
self._unknown_field_set = containers.UnknownFieldSet()
|
||||
self._unknown_field_set._extend(msg._unknown_field_set)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.MergeFromString"><code class="name flex">
|
||||
<span>def <span class="ident">MergeFromString</span></span>(<span>self, serialized)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def MergeFromString(self, serialized):
|
||||
serialized = memoryview(serialized)
|
||||
length = len(serialized)
|
||||
try:
|
||||
if self._InternalParse(serialized, 0, length) != length:
|
||||
# The only reason _InternalParse would return early is if it
|
||||
# encountered an end-group tag.
|
||||
raise message_mod.DecodeError('Unexpected end-group tag.')
|
||||
except (IndexError, TypeError):
|
||||
# Now ord(buf[p:p+1]) == ord('') gets TypeError.
|
||||
raise message_mod.DecodeError('Truncated message.')
|
||||
except struct.error as e:
|
||||
raise message_mod.DecodeError(e)
|
||||
return length # Return this for legacy reasons.</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.SerializePartialToString"><code class="name flex">
|
||||
<span>def <span class="ident">SerializePartialToString</span></span>(<span>self, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def SerializePartialToString(self, **kwargs):
|
||||
out = BytesIO()
|
||||
self._InternalSerialize(out.write, **kwargs)
|
||||
return out.getvalue()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.SerializeToString"><code class="name flex">
|
||||
<span>def <span class="ident">SerializeToString</span></span>(<span>self, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def SerializeToString(self, **kwargs):
|
||||
# Check if the message has all of its required fields set.
|
||||
if not self.IsInitialized():
|
||||
raise message_mod.EncodeError(
|
||||
'Message %s is missing required fields: %s' % (
|
||||
self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
|
||||
return self.SerializePartialToString(**kwargs)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.SetInParent"><code class="name flex">
|
||||
<span>def <span class="ident">SetInParent</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Sets the _cached_byte_size_dirty bit to true,
|
||||
and propagates this to our listener iff this was a state change.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def Modified(self):
|
||||
"""Sets the _cached_byte_size_dirty bit to true,
|
||||
and propagates this to our listener iff this was a state change.
|
||||
"""
|
||||
|
||||
# Note: Some callers check _cached_byte_size_dirty before calling
|
||||
# _Modified() as an extra optimization. So, if this method is ever
|
||||
# changed such that it does stuff even when _cached_byte_size_dirty is
|
||||
# already true, the callers need to be updated.
|
||||
if not self._cached_byte_size_dirty:
|
||||
self._cached_byte_size_dirty = True
|
||||
self._listener_for_children.dirty = True
|
||||
self._is_present_in_parent = True
|
||||
self._listener.Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.UnknownFields"><code class="name flex">
|
||||
<span>def <span class="ident">UnknownFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _UnknownFields(self):
|
||||
if self._unknown_field_set is None: # pylint: disable=protected-access
|
||||
# pylint: disable=protected-access
|
||||
self._unknown_field_set = containers.UnknownFieldSet()
|
||||
return self._unknown_field_set # pylint: disable=protected-access</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.apponly_pb2.ChannelSet.WhichOneof"><code class="name flex">
|
||||
<span>def <span class="ident">WhichOneof</span></span>(<span>self, oneof_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Returns the name of the currently set field inside a oneof, or None.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def WhichOneof(self, oneof_name):
|
||||
"""Returns the name of the currently set field inside a oneof, or None."""
|
||||
try:
|
||||
field = message_descriptor.oneofs_by_name[oneof_name]
|
||||
except KeyError:
|
||||
raise ValueError(
|
||||
'Protocol message has no oneof "%s" field.' % oneof_name)
|
||||
|
||||
nested_field = self._oneofs.get(field, None)
|
||||
if nested_field is not None and self.HasField(nested_field.name):
|
||||
return nested_field.name
|
||||
else:
|
||||
return None</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.apponly_pb2.ChannelSet" href="#meshtastic.apponly_pb2.ChannelSet">ChannelSet</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.ByteSize" href="#meshtastic.apponly_pb2.ChannelSet.ByteSize">ByteSize</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.Clear" href="#meshtastic.apponly_pb2.ChannelSet.Clear">Clear</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.ClearField" href="#meshtastic.apponly_pb2.ChannelSet.ClearField">ClearField</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.DESCRIPTOR" href="#meshtastic.apponly_pb2.ChannelSet.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.DiscardUnknownFields" href="#meshtastic.apponly_pb2.ChannelSet.DiscardUnknownFields">DiscardUnknownFields</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.FindInitializationErrors" href="#meshtastic.apponly_pb2.ChannelSet.FindInitializationErrors">FindInitializationErrors</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.FromString" href="#meshtastic.apponly_pb2.ChannelSet.FromString">FromString</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.HasField" href="#meshtastic.apponly_pb2.ChannelSet.HasField">HasField</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.IsInitialized" href="#meshtastic.apponly_pb2.ChannelSet.IsInitialized">IsInitialized</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.ListFields" href="#meshtastic.apponly_pb2.ChannelSet.ListFields">ListFields</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.MergeFrom" href="#meshtastic.apponly_pb2.ChannelSet.MergeFrom">MergeFrom</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.MergeFromString" href="#meshtastic.apponly_pb2.ChannelSet.MergeFromString">MergeFromString</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.RegisterExtension" href="#meshtastic.apponly_pb2.ChannelSet.RegisterExtension">RegisterExtension</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.SETTINGS_FIELD_NUMBER" href="#meshtastic.apponly_pb2.ChannelSet.SETTINGS_FIELD_NUMBER">SETTINGS_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.SerializePartialToString" href="#meshtastic.apponly_pb2.ChannelSet.SerializePartialToString">SerializePartialToString</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.SerializeToString" href="#meshtastic.apponly_pb2.ChannelSet.SerializeToString">SerializeToString</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.SetInParent" href="#meshtastic.apponly_pb2.ChannelSet.SetInParent">SetInParent</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.UnknownFields" href="#meshtastic.apponly_pb2.ChannelSet.UnknownFields">UnknownFields</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.WhichOneof" href="#meshtastic.apponly_pb2.ChannelSet.WhichOneof">WhichOneof</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2.ChannelSet.settings" href="#meshtastic.apponly_pb2.ChannelSet.settings">settings</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
53
docs/meshtastic/ble.html
Normal file
53
docs/meshtastic/ble.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.ble API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.ble</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
212
docs/meshtastic/ble_interface.html
Normal file
212
docs/meshtastic/ble_interface.html
Normal file
@@ -0,0 +1,212 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.ble_interface API documentation</title>
|
||||
<meta name="description" content="Bluetooth interface" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.ble_interface</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Bluetooth interface</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Bluetooth interface
|
||||
"""
|
||||
import logging
|
||||
import pygatt
|
||||
|
||||
|
||||
from .mesh_interface import MeshInterface
|
||||
|
||||
# Our standard BLE characteristics
|
||||
TORADIO_UUID = "f75c76d2-129e-4dad-a1dd-7866124401e7"
|
||||
FROMRADIO_UUID = "8ba2bcc2-ee02-4a55-a531-c525c5e454d5"
|
||||
FROMNUM_UUID = "ed9da18c-a800-4f66-a670-aa7547e34453"
|
||||
|
||||
|
||||
class BLEInterface(MeshInterface):
|
||||
"""A not quite ready - FIXME - BLE interface to devices"""
|
||||
|
||||
def __init__(self, address, noProto=False, debugOut=None):
|
||||
self.address = address
|
||||
if not noProto:
|
||||
self.adapter = pygatt.GATTToolBackend() # BGAPIBackend()
|
||||
self.adapter.start()
|
||||
logging.debug(f"Connecting to {self.address}")
|
||||
self.device = self.adapter.connect(address)
|
||||
else:
|
||||
self.adapter = None
|
||||
self.device = None
|
||||
logging.debug("Connected to device")
|
||||
# fromradio = self.device.char_read(FROMRADIO_UUID)
|
||||
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
|
||||
|
||||
self._readFromRadio() # read the initial responses
|
||||
|
||||
def handle_data(handle, data):
|
||||
self._handleFromRadio(data)
|
||||
|
||||
if self.device:
|
||||
self.device.subscribe(FROMNUM_UUID, callback=handle_data)
|
||||
|
||||
def _sendToRadioImpl(self, toRadio):
|
||||
"""Send a ToRadio protobuf to the device"""
|
||||
#logging.debug(f"Sending: {stripnl(toRadio)}")
|
||||
b = toRadio.SerializeToString()
|
||||
self.device.char_write(TORADIO_UUID, b)
|
||||
|
||||
def close(self):
|
||||
MeshInterface.close(self)
|
||||
if self.adapter:
|
||||
self.adapter.stop()
|
||||
|
||||
def _readFromRadio(self):
|
||||
if not self.noProto:
|
||||
wasEmpty = False
|
||||
while not wasEmpty:
|
||||
if self.device:
|
||||
b = self.device.char_read(FROMRADIO_UUID)
|
||||
wasEmpty = len(b) == 0
|
||||
if not wasEmpty:
|
||||
self._handleFromRadio(b)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.ble_interface.BLEInterface"><code class="flex name class">
|
||||
<span>class <span class="ident">BLEInterface</span></span>
|
||||
<span>(</span><span>address, noProto=False, debugOut=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A not quite ready - FIXME - BLE interface to devices</p>
|
||||
<p>Constructor</p>
|
||||
<p>Keyword Arguments:
|
||||
noProto – If True, don't try to run our protocol on the
|
||||
link - just be a dumb serial client.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class BLEInterface(MeshInterface):
|
||||
"""A not quite ready - FIXME - BLE interface to devices"""
|
||||
|
||||
def __init__(self, address, noProto=False, debugOut=None):
|
||||
self.address = address
|
||||
if not noProto:
|
||||
self.adapter = pygatt.GATTToolBackend() # BGAPIBackend()
|
||||
self.adapter.start()
|
||||
logging.debug(f"Connecting to {self.address}")
|
||||
self.device = self.adapter.connect(address)
|
||||
else:
|
||||
self.adapter = None
|
||||
self.device = None
|
||||
logging.debug("Connected to device")
|
||||
# fromradio = self.device.char_read(FROMRADIO_UUID)
|
||||
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
|
||||
|
||||
self._readFromRadio() # read the initial responses
|
||||
|
||||
def handle_data(handle, data):
|
||||
self._handleFromRadio(data)
|
||||
|
||||
if self.device:
|
||||
self.device.subscribe(FROMNUM_UUID, callback=handle_data)
|
||||
|
||||
def _sendToRadioImpl(self, toRadio):
|
||||
"""Send a ToRadio protobuf to the device"""
|
||||
#logging.debug(f"Sending: {stripnl(toRadio)}")
|
||||
b = toRadio.SerializeToString()
|
||||
self.device.char_write(TORADIO_UUID, b)
|
||||
|
||||
def close(self):
|
||||
MeshInterface.close(self)
|
||||
if self.adapter:
|
||||
self.adapter.stop()
|
||||
|
||||
def _readFromRadio(self):
|
||||
if not self.noProto:
|
||||
wasEmpty = False
|
||||
while not wasEmpty:
|
||||
if self.device:
|
||||
b = self.device.char_read(FROMRADIO_UUID)
|
||||
wasEmpty = len(b) == 0
|
||||
if not wasEmpty:
|
||||
self._handleFromRadio(b)</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="meshtastic.mesh_interface.MeshInterface" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface">MeshInterface</a></li>
|
||||
</ul>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="meshtastic.mesh_interface.MeshInterface" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface">MeshInterface</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.close" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.close">close</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getLongName" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getLongName">getLongName</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getMyNodeInfo" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getMyNodeInfo">getMyNodeInfo</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getMyUser" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getMyUser">getMyUser</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getNode" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getNode">getNode</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getShortName" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getShortName">getShortName</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.sendData" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendData">sendData</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.sendPosition" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendPosition">sendPosition</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.sendText" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendText">sendText</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.showInfo" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.showInfo">showInfo</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.showNodes" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.showNodes">showNodes</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.waitForConfig" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.waitForConfig">waitForConfig</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.ble_interface.BLEInterface" href="#meshtastic.ble_interface.BLEInterface">BLEInterface</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
1741
docs/meshtastic/channel_pb2.html
Normal file
1741
docs/meshtastic/channel_pb2.html
Normal file
File diff suppressed because it is too large
Load Diff
2241
docs/meshtastic/deviceonly_pb2.html
Normal file
2241
docs/meshtastic/deviceonly_pb2.html
Normal file
File diff suppressed because it is too large
Load Diff
746
docs/meshtastic/environmental_measurement_pb2.html
Normal file
746
docs/meshtastic/environmental_measurement_pb2.html
Normal file
@@ -0,0 +1,746 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.environmental_measurement_pb2 API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.environmental_measurement_pb2</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: environmental_measurement.proto
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='environmental_measurement.proto',
|
||||
package='',
|
||||
syntax='proto3',
|
||||
serialized_options=b'Z!github.com/meshtastic/gomeshproto',
|
||||
serialized_pb=b'\n\x1f\x65nvironmental_measurement.proto\"g\n\x18\x45nvironmentalMeasurement\x12\x13\n\x0btemperature\x18\x01 \x01(\x02\x12\x19\n\x11relative_humidity\x18\x02 \x01(\x02\x12\x1b\n\x13\x62\x61rometric_pressure\x18\x03 \x01(\x02\x42#Z!github.com/meshtastic/gomeshprotob\x06proto3'
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
_ENVIRONMENTALMEASUREMENT = _descriptor.Descriptor(
|
||||
name='EnvironmentalMeasurement',
|
||||
full_name='EnvironmentalMeasurement',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='temperature', full_name='EnvironmentalMeasurement.temperature', index=0,
|
||||
number=1, type=2, cpp_type=6, label=1,
|
||||
has_default_value=False, default_value=float(0),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='relative_humidity', full_name='EnvironmentalMeasurement.relative_humidity', index=1,
|
||||
number=2, type=2, cpp_type=6, label=1,
|
||||
has_default_value=False, default_value=float(0),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='barometric_pressure', full_name='EnvironmentalMeasurement.barometric_pressure', index=2,
|
||||
number=3, type=2, cpp_type=6, label=1,
|
||||
has_default_value=False, default_value=float(0),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=35,
|
||||
serialized_end=138,
|
||||
)
|
||||
|
||||
DESCRIPTOR.message_types_by_name['EnvironmentalMeasurement'] = _ENVIRONMENTALMEASUREMENT
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
EnvironmentalMeasurement = _reflection.GeneratedProtocolMessageType('EnvironmentalMeasurement', (_message.Message,), {
|
||||
'DESCRIPTOR' : _ENVIRONMENTALMEASUREMENT,
|
||||
'__module__' : 'environmental_measurement_pb2'
|
||||
# @@protoc_insertion_point(class_scope:EnvironmentalMeasurement)
|
||||
})
|
||||
_sym_db.RegisterMessage(EnvironmentalMeasurement)
|
||||
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement"><code class="flex name class">
|
||||
<span>class <span class="ident">EnvironmentalMeasurement</span></span>
|
||||
<span>(</span><span>**kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Abstract base class for protocol messages.</p>
|
||||
<p>Protocol message classes are almost always generated by the protocol
|
||||
compiler.
|
||||
These generated types subclass Message and implement the methods
|
||||
shown below.</p></div>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>google.protobuf.message.Message</li>
|
||||
</ul>
|
||||
<h3>Class variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.BAROMETRIC_PRESSURE_FIELD_NUMBER"><code class="name">var <span class="ident">BAROMETRIC_PRESSURE_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.RELATIVE_HUMIDITY_FIELD_NUMBER"><code class="name">var <span class="ident">RELATIVE_HUMIDITY_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.TEMPERATURE_FIELD_NUMBER"><code class="name">var <span class="ident">TEMPERATURE_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Static methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.FromString"><code class="name flex">
|
||||
<span>def <span class="ident">FromString</span></span>(<span>s)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def FromString(s):
|
||||
message = cls()
|
||||
message.MergeFromString(s)
|
||||
return message</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.RegisterExtension"><code class="name flex">
|
||||
<span>def <span class="ident">RegisterExtension</span></span>(<span>extension_handle)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def RegisterExtension(extension_handle):
|
||||
extension_handle.containing_type = cls.DESCRIPTOR
|
||||
# TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
|
||||
# pylint: disable=protected-access
|
||||
cls.DESCRIPTOR.file.pool._AddExtensionDescriptor(extension_handle)
|
||||
_AttachFieldHelpers(cls, extension_handle)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Instance variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.barometric_pressure"><code class="name">var <span class="ident">barometric_pressure</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for barometric_pressure.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
# TODO(protobuf-team): This may be broken since there may not be
|
||||
# default_value. Combine with has_default_value somehow.
|
||||
return self._fields.get(field, default_value)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.relative_humidity"><code class="name">var <span class="ident">relative_humidity</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for relative_humidity.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
# TODO(protobuf-team): This may be broken since there may not be
|
||||
# default_value. Combine with has_default_value somehow.
|
||||
return self._fields.get(field, default_value)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.temperature"><code class="name">var <span class="ident">temperature</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for temperature.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
# TODO(protobuf-team): This may be broken since there may not be
|
||||
# default_value. Combine with has_default_value somehow.
|
||||
return self._fields.get(field, default_value)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.ByteSize"><code class="name flex">
|
||||
<span>def <span class="ident">ByteSize</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ByteSize(self):
|
||||
if not self._cached_byte_size_dirty:
|
||||
return self._cached_byte_size
|
||||
|
||||
size = 0
|
||||
descriptor = self.DESCRIPTOR
|
||||
if descriptor.GetOptions().map_entry:
|
||||
# Fields of map entry should always be serialized.
|
||||
size = descriptor.fields_by_name['key']._sizer(self.key)
|
||||
size += descriptor.fields_by_name['value']._sizer(self.value)
|
||||
else:
|
||||
for field_descriptor, field_value in self.ListFields():
|
||||
size += field_descriptor._sizer(field_value)
|
||||
for tag_bytes, value_bytes in self._unknown_fields:
|
||||
size += len(tag_bytes) + len(value_bytes)
|
||||
|
||||
self._cached_byte_size = size
|
||||
self._cached_byte_size_dirty = False
|
||||
self._listener_for_children.dirty = False
|
||||
return size</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.Clear"><code class="name flex">
|
||||
<span>def <span class="ident">Clear</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _Clear(self):
|
||||
# Clear fields.
|
||||
self._fields = {}
|
||||
self._unknown_fields = ()
|
||||
# pylint: disable=protected-access
|
||||
if self._unknown_field_set is not None:
|
||||
self._unknown_field_set._clear()
|
||||
self._unknown_field_set = None
|
||||
|
||||
self._oneofs = {}
|
||||
self._Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.ClearField"><code class="name flex">
|
||||
<span>def <span class="ident">ClearField</span></span>(<span>self, field_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ClearField(self, field_name):
|
||||
try:
|
||||
field = message_descriptor.fields_by_name[field_name]
|
||||
except KeyError:
|
||||
try:
|
||||
field = message_descriptor.oneofs_by_name[field_name]
|
||||
if field in self._oneofs:
|
||||
field = self._oneofs[field]
|
||||
else:
|
||||
return
|
||||
except KeyError:
|
||||
raise ValueError('Protocol message %s has no "%s" field.' %
|
||||
(message_descriptor.name, field_name))
|
||||
|
||||
if field in self._fields:
|
||||
# To match the C++ implementation, we need to invalidate iterators
|
||||
# for map fields when ClearField() happens.
|
||||
if hasattr(self._fields[field], 'InvalidateIterators'):
|
||||
self._fields[field].InvalidateIterators()
|
||||
|
||||
# Note: If the field is a sub-message, its listener will still point
|
||||
# at us. That's fine, because the worst than can happen is that it
|
||||
# will call _Modified() and invalidate our byte size. Big deal.
|
||||
del self._fields[field]
|
||||
|
||||
if self._oneofs.get(field.containing_oneof, None) is field:
|
||||
del self._oneofs[field.containing_oneof]
|
||||
|
||||
# Always call _Modified() -- even if nothing was changed, this is
|
||||
# a mutating method, and thus calling it should cause the field to become
|
||||
# present in the parent message.
|
||||
self._Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.DiscardUnknownFields"><code class="name flex">
|
||||
<span>def <span class="ident">DiscardUnknownFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _DiscardUnknownFields(self):
|
||||
self._unknown_fields = []
|
||||
self._unknown_field_set = None # pylint: disable=protected-access
|
||||
for field, value in self.ListFields():
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if _IsMapField(field):
|
||||
if _IsMessageMapField(field):
|
||||
for key in value:
|
||||
value[key].DiscardUnknownFields()
|
||||
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
for sub_message in value:
|
||||
sub_message.DiscardUnknownFields()
|
||||
else:
|
||||
value.DiscardUnknownFields()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.FindInitializationErrors"><code class="name flex">
|
||||
<span>def <span class="ident">FindInitializationErrors</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Finds required fields which are not initialized.</p>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>A list of strings.
|
||||
Each string is a path to an uninitialized field from
|
||||
the top-level message, e.g. "foo.bar[5].baz".</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def FindInitializationErrors(self):
|
||||
"""Finds required fields which are not initialized.
|
||||
|
||||
Returns:
|
||||
A list of strings. Each string is a path to an uninitialized field from
|
||||
the top-level message, e.g. "foo.bar[5].baz".
|
||||
"""
|
||||
|
||||
errors = [] # simplify things
|
||||
|
||||
for field in required_fields:
|
||||
if not self.HasField(field.name):
|
||||
errors.append(field.name)
|
||||
|
||||
for field, value in self.ListFields():
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if field.is_extension:
|
||||
name = '(%s)' % field.full_name
|
||||
else:
|
||||
name = field.name
|
||||
|
||||
if _IsMapField(field):
|
||||
if _IsMessageMapField(field):
|
||||
for key in value:
|
||||
element = value[key]
|
||||
prefix = '%s[%s].' % (name, key)
|
||||
sub_errors = element.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
else:
|
||||
# ScalarMaps can't have any initialization errors.
|
||||
pass
|
||||
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
for i in range(len(value)):
|
||||
element = value[i]
|
||||
prefix = '%s[%d].' % (name, i)
|
||||
sub_errors = element.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
else:
|
||||
prefix = name + '.'
|
||||
sub_errors = value.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
|
||||
return errors</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.HasField"><code class="name flex">
|
||||
<span>def <span class="ident">HasField</span></span>(<span>self, field_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def HasField(self, field_name):
|
||||
try:
|
||||
field = hassable_fields[field_name]
|
||||
except KeyError:
|
||||
raise ValueError(error_msg % (message_descriptor.full_name, field_name))
|
||||
|
||||
if isinstance(field, descriptor_mod.OneofDescriptor):
|
||||
try:
|
||||
return HasField(self, self._oneofs[field].name)
|
||||
except KeyError:
|
||||
return False
|
||||
else:
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
value = self._fields.get(field)
|
||||
return value is not None and value._is_present_in_parent
|
||||
else:
|
||||
return field in self._fields</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.IsInitialized"><code class="name flex">
|
||||
<span>def <span class="ident">IsInitialized</span></span>(<span>self, errors=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Checks if all required fields of a message are set.</p>
|
||||
<h2 id="args">Args</h2>
|
||||
<dl>
|
||||
<dt><strong><code>errors</code></strong></dt>
|
||||
<dd>A list which, if provided, will be populated with the field
|
||||
paths of all missing required fields.</dd>
|
||||
</dl>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>True iff the specified message has all required fields set.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def IsInitialized(self, errors=None):
|
||||
"""Checks if all required fields of a message are set.
|
||||
|
||||
Args:
|
||||
errors: A list which, if provided, will be populated with the field
|
||||
paths of all missing required fields.
|
||||
|
||||
Returns:
|
||||
True iff the specified message has all required fields set.
|
||||
"""
|
||||
|
||||
# Performance is critical so we avoid HasField() and ListFields().
|
||||
|
||||
for field in required_fields:
|
||||
if (field not in self._fields or
|
||||
(field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
|
||||
not self._fields[field]._is_present_in_parent)):
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
|
||||
for field, value in list(self._fields.items()): # dict can change size!
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
if (field.message_type.has_options and
|
||||
field.message_type.GetOptions().map_entry):
|
||||
continue
|
||||
for element in value:
|
||||
if not element.IsInitialized():
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
elif value._is_present_in_parent and not value.IsInitialized():
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
|
||||
return True</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.ListFields"><code class="name flex">
|
||||
<span>def <span class="ident">ListFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ListFields(self):
|
||||
all_fields = [item for item in self._fields.items() if _IsPresent(item)]
|
||||
all_fields.sort(key = lambda item: item[0].number)
|
||||
return all_fields</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.MergeFrom"><code class="name flex">
|
||||
<span>def <span class="ident">MergeFrom</span></span>(<span>self, msg)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def MergeFrom(self, msg):
|
||||
if not isinstance(msg, cls):
|
||||
raise TypeError(
|
||||
'Parameter to MergeFrom() must be instance of same class: '
|
||||
'expected %s got %s.' % (_FullyQualifiedClassName(cls),
|
||||
_FullyQualifiedClassName(msg.__class__)))
|
||||
|
||||
assert msg is not self
|
||||
self._Modified()
|
||||
|
||||
fields = self._fields
|
||||
|
||||
for field, value in msg._fields.items():
|
||||
if field.label == LABEL_REPEATED:
|
||||
field_value = fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
fields[field] = field_value
|
||||
field_value.MergeFrom(value)
|
||||
elif field.cpp_type == CPPTYPE_MESSAGE:
|
||||
if value._is_present_in_parent:
|
||||
field_value = fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
fields[field] = field_value
|
||||
field_value.MergeFrom(value)
|
||||
else:
|
||||
self._fields[field] = value
|
||||
if field.containing_oneof:
|
||||
self._UpdateOneofState(field)
|
||||
|
||||
if msg._unknown_fields:
|
||||
if not self._unknown_fields:
|
||||
self._unknown_fields = []
|
||||
self._unknown_fields.extend(msg._unknown_fields)
|
||||
# pylint: disable=protected-access
|
||||
if self._unknown_field_set is None:
|
||||
self._unknown_field_set = containers.UnknownFieldSet()
|
||||
self._unknown_field_set._extend(msg._unknown_field_set)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.MergeFromString"><code class="name flex">
|
||||
<span>def <span class="ident">MergeFromString</span></span>(<span>self, serialized)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def MergeFromString(self, serialized):
|
||||
serialized = memoryview(serialized)
|
||||
length = len(serialized)
|
||||
try:
|
||||
if self._InternalParse(serialized, 0, length) != length:
|
||||
# The only reason _InternalParse would return early is if it
|
||||
# encountered an end-group tag.
|
||||
raise message_mod.DecodeError('Unexpected end-group tag.')
|
||||
except (IndexError, TypeError):
|
||||
# Now ord(buf[p:p+1]) == ord('') gets TypeError.
|
||||
raise message_mod.DecodeError('Truncated message.')
|
||||
except struct.error as e:
|
||||
raise message_mod.DecodeError(e)
|
||||
return length # Return this for legacy reasons.</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.SerializePartialToString"><code class="name flex">
|
||||
<span>def <span class="ident">SerializePartialToString</span></span>(<span>self, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def SerializePartialToString(self, **kwargs):
|
||||
out = BytesIO()
|
||||
self._InternalSerialize(out.write, **kwargs)
|
||||
return out.getvalue()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.SerializeToString"><code class="name flex">
|
||||
<span>def <span class="ident">SerializeToString</span></span>(<span>self, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def SerializeToString(self, **kwargs):
|
||||
# Check if the message has all of its required fields set.
|
||||
if not self.IsInitialized():
|
||||
raise message_mod.EncodeError(
|
||||
'Message %s is missing required fields: %s' % (
|
||||
self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
|
||||
return self.SerializePartialToString(**kwargs)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.SetInParent"><code class="name flex">
|
||||
<span>def <span class="ident">SetInParent</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Sets the _cached_byte_size_dirty bit to true,
|
||||
and propagates this to our listener iff this was a state change.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def Modified(self):
|
||||
"""Sets the _cached_byte_size_dirty bit to true,
|
||||
and propagates this to our listener iff this was a state change.
|
||||
"""
|
||||
|
||||
# Note: Some callers check _cached_byte_size_dirty before calling
|
||||
# _Modified() as an extra optimization. So, if this method is ever
|
||||
# changed such that it does stuff even when _cached_byte_size_dirty is
|
||||
# already true, the callers need to be updated.
|
||||
if not self._cached_byte_size_dirty:
|
||||
self._cached_byte_size_dirty = True
|
||||
self._listener_for_children.dirty = True
|
||||
self._is_present_in_parent = True
|
||||
self._listener.Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.UnknownFields"><code class="name flex">
|
||||
<span>def <span class="ident">UnknownFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _UnknownFields(self):
|
||||
if self._unknown_field_set is None: # pylint: disable=protected-access
|
||||
# pylint: disable=protected-access
|
||||
self._unknown_field_set = containers.UnknownFieldSet()
|
||||
return self._unknown_field_set # pylint: disable=protected-access</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.WhichOneof"><code class="name flex">
|
||||
<span>def <span class="ident">WhichOneof</span></span>(<span>self, oneof_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Returns the name of the currently set field inside a oneof, or None.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def WhichOneof(self, oneof_name):
|
||||
"""Returns the name of the currently set field inside a oneof, or None."""
|
||||
try:
|
||||
field = message_descriptor.oneofs_by_name[oneof_name]
|
||||
except KeyError:
|
||||
raise ValueError(
|
||||
'Protocol message has no oneof "%s" field.' % oneof_name)
|
||||
|
||||
nested_field = self._oneofs.get(field, None)
|
||||
if nested_field is not None and self.HasField(nested_field.name):
|
||||
return nested_field.name
|
||||
else:
|
||||
return None</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement">EnvironmentalMeasurement</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.BAROMETRIC_PRESSURE_FIELD_NUMBER" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.BAROMETRIC_PRESSURE_FIELD_NUMBER">BAROMETRIC_PRESSURE_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.ByteSize" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.ByteSize">ByteSize</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.Clear" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.Clear">Clear</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.ClearField" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.ClearField">ClearField</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.DESCRIPTOR" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.DiscardUnknownFields" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.DiscardUnknownFields">DiscardUnknownFields</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.FindInitializationErrors" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.FindInitializationErrors">FindInitializationErrors</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.FromString" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.FromString">FromString</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.HasField" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.HasField">HasField</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.IsInitialized" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.IsInitialized">IsInitialized</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.ListFields" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.ListFields">ListFields</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.MergeFrom" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.MergeFrom">MergeFrom</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.MergeFromString" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.MergeFromString">MergeFromString</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.RELATIVE_HUMIDITY_FIELD_NUMBER" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.RELATIVE_HUMIDITY_FIELD_NUMBER">RELATIVE_HUMIDITY_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.RegisterExtension" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.RegisterExtension">RegisterExtension</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.SerializePartialToString" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.SerializePartialToString">SerializePartialToString</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.SerializeToString" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.SerializeToString">SerializeToString</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.SetInParent" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.SetInParent">SetInParent</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.TEMPERATURE_FIELD_NUMBER" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.TEMPERATURE_FIELD_NUMBER">TEMPERATURE_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.UnknownFields" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.UnknownFields">UnknownFields</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.WhichOneof" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.WhichOneof">WhichOneof</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.barometric_pressure" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.barometric_pressure">barometric_pressure</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.relative_humidity" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.relative_humidity">relative_humidity</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.temperature" href="#meshtastic.environmental_measurement_pb2.EnvironmentalMeasurement.temperature">temperature</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
380
docs/meshtastic/globals.html
Normal file
380
docs/meshtastic/globals.html
Normal file
@@ -0,0 +1,380 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.globals API documentation</title>
|
||||
<meta name="description" content="Globals singleton class …" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.globals</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Globals singleton class.</p>
|
||||
<p>Instead of using a global, stuff your variables in this "trash can".
|
||||
This is not much better than using python's globals, but it allows
|
||||
us to better test meshtastic. Plus, there are some weird python
|
||||
global issues/gotcha that we can hopefully avoid by using this
|
||||
class instead.</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Globals singleton class.
|
||||
|
||||
Instead of using a global, stuff your variables in this "trash can".
|
||||
This is not much better than using python's globals, but it allows
|
||||
us to better test meshtastic. Plus, there are some weird python
|
||||
global issues/gotcha that we can hopefully avoid by using this
|
||||
class instead.
|
||||
|
||||
"""
|
||||
|
||||
class Globals:
|
||||
"""Globals class is a Singleton."""
|
||||
__instance = None
|
||||
|
||||
@staticmethod
|
||||
def getInstance():
|
||||
"""Get an instance of the Globals class."""
|
||||
if Globals.__instance is None:
|
||||
Globals()
|
||||
return Globals.__instance
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor for the Globals CLass"""
|
||||
if Globals.__instance is not None:
|
||||
raise Exception("This class is a singleton")
|
||||
else:
|
||||
Globals.__instance = self
|
||||
self.args = None
|
||||
self.parser = None
|
||||
self.target_node = None
|
||||
self.channel_index = None
|
||||
|
||||
def reset(self):
|
||||
"""Reset all of our globals. If you add a member, add it to this method, too."""
|
||||
self.args = None
|
||||
self.parser = None
|
||||
self.target_node = None
|
||||
self.channel_index = None
|
||||
|
||||
def set_args(self, args):
|
||||
"""Set the args"""
|
||||
self.args = args
|
||||
|
||||
def set_parser(self, parser):
|
||||
"""Set the parser"""
|
||||
self.parser = parser
|
||||
|
||||
def set_target_node(self, target_node):
|
||||
"""Set the target_node"""
|
||||
self.target_node = target_node
|
||||
|
||||
def set_channel_index(self, channel_index):
|
||||
"""Set the channel_index"""
|
||||
self.channel_index = channel_index
|
||||
|
||||
def get_args(self):
|
||||
"""Get args"""
|
||||
return self.args
|
||||
|
||||
def get_parser(self):
|
||||
"""Get parser"""
|
||||
return self.parser
|
||||
|
||||
def get_target_node(self):
|
||||
"""Get target_node"""
|
||||
return self.target_node
|
||||
|
||||
def get_channel_index(self):
|
||||
"""Get channel_index"""
|
||||
return self.channel_index</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.globals.Globals"><code class="flex name class">
|
||||
<span>class <span class="ident">Globals</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Globals class is a Singleton.</p>
|
||||
<p>Constructor for the Globals CLass</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class Globals:
|
||||
"""Globals class is a Singleton."""
|
||||
__instance = None
|
||||
|
||||
@staticmethod
|
||||
def getInstance():
|
||||
"""Get an instance of the Globals class."""
|
||||
if Globals.__instance is None:
|
||||
Globals()
|
||||
return Globals.__instance
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor for the Globals CLass"""
|
||||
if Globals.__instance is not None:
|
||||
raise Exception("This class is a singleton")
|
||||
else:
|
||||
Globals.__instance = self
|
||||
self.args = None
|
||||
self.parser = None
|
||||
self.target_node = None
|
||||
self.channel_index = None
|
||||
|
||||
def reset(self):
|
||||
"""Reset all of our globals. If you add a member, add it to this method, too."""
|
||||
self.args = None
|
||||
self.parser = None
|
||||
self.target_node = None
|
||||
self.channel_index = None
|
||||
|
||||
def set_args(self, args):
|
||||
"""Set the args"""
|
||||
self.args = args
|
||||
|
||||
def set_parser(self, parser):
|
||||
"""Set the parser"""
|
||||
self.parser = parser
|
||||
|
||||
def set_target_node(self, target_node):
|
||||
"""Set the target_node"""
|
||||
self.target_node = target_node
|
||||
|
||||
def set_channel_index(self, channel_index):
|
||||
"""Set the channel_index"""
|
||||
self.channel_index = channel_index
|
||||
|
||||
def get_args(self):
|
||||
"""Get args"""
|
||||
return self.args
|
||||
|
||||
def get_parser(self):
|
||||
"""Get parser"""
|
||||
return self.parser
|
||||
|
||||
def get_target_node(self):
|
||||
"""Get target_node"""
|
||||
return self.target_node
|
||||
|
||||
def get_channel_index(self):
|
||||
"""Get channel_index"""
|
||||
return self.channel_index</code></pre>
|
||||
</details>
|
||||
<h3>Static methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.globals.Globals.getInstance"><code class="name flex">
|
||||
<span>def <span class="ident">getInstance</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Get an instance of the Globals class.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@staticmethod
|
||||
def getInstance():
|
||||
"""Get an instance of the Globals class."""
|
||||
if Globals.__instance is None:
|
||||
Globals()
|
||||
return Globals.__instance</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.globals.Globals.get_args"><code class="name flex">
|
||||
<span>def <span class="ident">get_args</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Get args</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def get_args(self):
|
||||
"""Get args"""
|
||||
return self.args</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.globals.Globals.get_channel_index"><code class="name flex">
|
||||
<span>def <span class="ident">get_channel_index</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Get channel_index</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def get_channel_index(self):
|
||||
"""Get channel_index"""
|
||||
return self.channel_index</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.globals.Globals.get_parser"><code class="name flex">
|
||||
<span>def <span class="ident">get_parser</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Get parser</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def get_parser(self):
|
||||
"""Get parser"""
|
||||
return self.parser</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.globals.Globals.get_target_node"><code class="name flex">
|
||||
<span>def <span class="ident">get_target_node</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Get target_node</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def get_target_node(self):
|
||||
"""Get target_node"""
|
||||
return self.target_node</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.globals.Globals.reset"><code class="name flex">
|
||||
<span>def <span class="ident">reset</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Reset all of our globals. If you add a member, add it to this method, too.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def reset(self):
|
||||
"""Reset all of our globals. If you add a member, add it to this method, too."""
|
||||
self.args = None
|
||||
self.parser = None
|
||||
self.target_node = None
|
||||
self.channel_index = None</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.globals.Globals.set_args"><code class="name flex">
|
||||
<span>def <span class="ident">set_args</span></span>(<span>self, args)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Set the args</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def set_args(self, args):
|
||||
"""Set the args"""
|
||||
self.args = args</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.globals.Globals.set_channel_index"><code class="name flex">
|
||||
<span>def <span class="ident">set_channel_index</span></span>(<span>self, channel_index)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Set the channel_index</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def set_channel_index(self, channel_index):
|
||||
"""Set the channel_index"""
|
||||
self.channel_index = channel_index</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.globals.Globals.set_parser"><code class="name flex">
|
||||
<span>def <span class="ident">set_parser</span></span>(<span>self, parser)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Set the parser</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def set_parser(self, parser):
|
||||
"""Set the parser"""
|
||||
self.parser = parser</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.globals.Globals.set_target_node"><code class="name flex">
|
||||
<span>def <span class="ident">set_target_node</span></span>(<span>self, target_node)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Set the target_node</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def set_target_node(self, target_node):
|
||||
"""Set the target_node"""
|
||||
self.target_node = target_node</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.globals.Globals" href="#meshtastic.globals.Globals">Globals</a></code></h4>
|
||||
<ul class="two-column">
|
||||
<li><code><a title="meshtastic.globals.Globals.getInstance" href="#meshtastic.globals.Globals.getInstance">getInstance</a></code></li>
|
||||
<li><code><a title="meshtastic.globals.Globals.get_args" href="#meshtastic.globals.Globals.get_args">get_args</a></code></li>
|
||||
<li><code><a title="meshtastic.globals.Globals.get_channel_index" href="#meshtastic.globals.Globals.get_channel_index">get_channel_index</a></code></li>
|
||||
<li><code><a title="meshtastic.globals.Globals.get_parser" href="#meshtastic.globals.Globals.get_parser">get_parser</a></code></li>
|
||||
<li><code><a title="meshtastic.globals.Globals.get_target_node" href="#meshtastic.globals.Globals.get_target_node">get_target_node</a></code></li>
|
||||
<li><code><a title="meshtastic.globals.Globals.reset" href="#meshtastic.globals.Globals.reset">reset</a></code></li>
|
||||
<li><code><a title="meshtastic.globals.Globals.set_args" href="#meshtastic.globals.Globals.set_args">set_args</a></code></li>
|
||||
<li><code><a title="meshtastic.globals.Globals.set_channel_index" href="#meshtastic.globals.Globals.set_channel_index">set_channel_index</a></code></li>
|
||||
<li><code><a title="meshtastic.globals.Globals.set_parser" href="#meshtastic.globals.Globals.set_parser">set_parser</a></code></li>
|
||||
<li><code><a title="meshtastic.globals.Globals.set_target_node" href="#meshtastic.globals.Globals.set_target_node">set_target_node</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
538
docs/meshtastic/index.html
Normal file
538
docs/meshtastic/index.html
Normal file
@@ -0,0 +1,538 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic API documentation</title>
|
||||
<meta name="description" content="an API for Meshtastic devices …" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Package <code>meshtastic</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<h1 id="an-api-for-meshtastic-devices">an API for Meshtastic devices</h1>
|
||||
<p>Primary class: SerialInterface
|
||||
Install with pip: "<a href="https://pypi.org/project/meshtastic/">pip3 install meshtastic</a>"
|
||||
Source code on <a href="https://github.com/meshtastic/Meshtastic-python">github</a></p>
|
||||
<p>properties of SerialInterface:</p>
|
||||
<ul>
|
||||
<li>radioConfig - Current radio configuration and device settings, if you write to this the new settings will be applied to
|
||||
the device.</li>
|
||||
<li>nodes - The database of received nodes.
|
||||
Includes always up-to-date location and username information for each
|
||||
node in the mesh.
|
||||
This is a read-only datastructure.</li>
|
||||
<li>nodesByNum - like "nodes" but keyed by nodeNum instead of nodeId</li>
|
||||
<li>myInfo - Contains read-only information about the local radio device (software version, hardware version, etc)</li>
|
||||
</ul>
|
||||
<h1 id="published-pubsub-topics">Published PubSub topics</h1>
|
||||
<p>We use a <a href="https://pypubsub.readthedocs.io/en/v4.0.3/">publish-subscribe</a> model to communicate asynchronous events.
|
||||
Available
|
||||
topics:</p>
|
||||
<ul>
|
||||
<li>meshtastic.connection.established - published once we've successfully connected to the radio and downloaded the node DB</li>
|
||||
<li>meshtastic.connection.lost - published once we've lost our link to the radio</li>
|
||||
<li>meshtastic.receive.text(packet) - delivers a received packet as a dictionary, if you only care about a particular
|
||||
type of packet, you should subscribe to the full topic name.
|
||||
If you want to see all packets, simply subscribe to "meshtastic.receive".</li>
|
||||
<li>meshtastic.receive.position(packet)</li>
|
||||
<li>meshtastic.receive.user(packet)</li>
|
||||
<li>meshtastic.receive.data.portnum(packet) (where portnum is an integer or well known PortNum enum)</li>
|
||||
<li>meshtastic.node.updated(node = NodeInfo) - published when a node in the DB changes (appears, location changed, username changed, etc…)</li>
|
||||
</ul>
|
||||
<p>We receive position, user, or data packets from the mesh.
|
||||
You probably only care about meshtastic.receive.data.
|
||||
The first argument for
|
||||
that publish will be the packet.
|
||||
Text or binary data packets (from sendData or sendText) will both arrive this way.
|
||||
If you print packet
|
||||
you'll see the fields in the dictionary.
|
||||
decoded.data.payload will contain the raw bytes that were sent.
|
||||
If the packet was sent with
|
||||
sendText, decoded.data.text will <strong>also</strong> be populated with the decoded string.
|
||||
For ASCII these two strings will be the same, but for
|
||||
unicode scripts they can be different.</p>
|
||||
<h1 id="example-usage">Example Usage</h1>
|
||||
<pre><code>import meshtastic
|
||||
import meshtastic.serial_interface
|
||||
from pubsub import pub
|
||||
|
||||
def onReceive(packet, interface): # called when a packet arrives
|
||||
print(f"Received: {packet}")
|
||||
|
||||
def onConnection(interface, topic=pub.AUTO_TOPIC): # called when we (re)connect to the radio
|
||||
# defaults to broadcast, specify a destination ID if you wish
|
||||
interface.sendText("hello mesh")
|
||||
|
||||
pub.subscribe(onReceive, "meshtastic.receive")
|
||||
pub.subscribe(onConnection, "meshtastic.connection.established")
|
||||
# By default will try to find a meshtastic device, otherwise provide a device path like /dev/ttyUSB0
|
||||
interface = meshtastic.serial_interface.SerialInterface()
|
||||
|
||||
</code></pre>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""
|
||||
# an API for Meshtastic devices
|
||||
|
||||
Primary class: SerialInterface
|
||||
Install with pip: "[pip3 install meshtastic](https://pypi.org/project/meshtastic/)"
|
||||
Source code on [github](https://github.com/meshtastic/Meshtastic-python)
|
||||
|
||||
properties of SerialInterface:
|
||||
|
||||
- radioConfig - Current radio configuration and device settings, if you write to this the new settings will be applied to
|
||||
the device.
|
||||
- nodes - The database of received nodes. Includes always up-to-date location and username information for each
|
||||
node in the mesh. This is a read-only datastructure.
|
||||
- nodesByNum - like "nodes" but keyed by nodeNum instead of nodeId
|
||||
- myInfo - Contains read-only information about the local radio device (software version, hardware version, etc)
|
||||
|
||||
# Published PubSub topics
|
||||
|
||||
We use a [publish-subscribe](https://pypubsub.readthedocs.io/en/v4.0.3/) model to communicate asynchronous events. Available
|
||||
topics:
|
||||
|
||||
- meshtastic.connection.established - published once we've successfully connected to the radio and downloaded the node DB
|
||||
- meshtastic.connection.lost - published once we've lost our link to the radio
|
||||
- meshtastic.receive.text(packet) - delivers a received packet as a dictionary, if you only care about a particular
|
||||
type of packet, you should subscribe to the full topic name. If you want to see all packets, simply subscribe to "meshtastic.receive".
|
||||
- meshtastic.receive.position(packet)
|
||||
- meshtastic.receive.user(packet)
|
||||
- meshtastic.receive.data.portnum(packet) (where portnum is an integer or well known PortNum enum)
|
||||
- meshtastic.node.updated(node = NodeInfo) - published when a node in the DB changes (appears, location changed, username changed, etc...)
|
||||
|
||||
We receive position, user, or data packets from the mesh. You probably only care about meshtastic.receive.data. The first argument for
|
||||
that publish will be the packet. Text or binary data packets (from sendData or sendText) will both arrive this way. If you print packet
|
||||
you'll see the fields in the dictionary. decoded.data.payload will contain the raw bytes that were sent. If the packet was sent with
|
||||
sendText, decoded.data.text will **also** be populated with the decoded string. For ASCII these two strings will be the same, but for
|
||||
unicode scripts they can be different.
|
||||
|
||||
# Example Usage
|
||||
```
|
||||
import meshtastic
|
||||
import meshtastic.serial_interface
|
||||
from pubsub import pub
|
||||
|
||||
def onReceive(packet, interface): # called when a packet arrives
|
||||
print(f"Received: {packet}")
|
||||
|
||||
def onConnection(interface, topic=pub.AUTO_TOPIC): # called when we (re)connect to the radio
|
||||
# defaults to broadcast, specify a destination ID if you wish
|
||||
interface.sendText("hello mesh")
|
||||
|
||||
pub.subscribe(onReceive, "meshtastic.receive")
|
||||
pub.subscribe(onConnection, "meshtastic.connection.established")
|
||||
# By default will try to find a meshtastic device, otherwise provide a device path like /dev/ttyUSB0
|
||||
interface = meshtastic.serial_interface.SerialInterface()
|
||||
|
||||
```
|
||||
|
||||
"""
|
||||
|
||||
import base64
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
import socket
|
||||
import sys
|
||||
import stat
|
||||
import threading
|
||||
import traceback
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import *
|
||||
import serial
|
||||
import timeago
|
||||
import google.protobuf.json_format
|
||||
import pygatt
|
||||
from pubsub import pub
|
||||
from dotmap import DotMap
|
||||
from tabulate import tabulate
|
||||
from google.protobuf.json_format import MessageToJson
|
||||
from .util import fixme, catchAndIgnore, stripnl, DeferredExecution, Timeout
|
||||
from .node import Node
|
||||
from . import mesh_pb2, portnums_pb2, apponly_pb2, admin_pb2, environmental_measurement_pb2, remote_hardware_pb2, channel_pb2, radioconfig_pb2, util
|
||||
|
||||
# Note: To follow PEP224, comments should be after the module variable.
|
||||
|
||||
LOCAL_ADDR = "^local"
|
||||
"""A special ID that means the local node"""
|
||||
|
||||
BROADCAST_NUM = 0xffffffff
|
||||
"""if using 8 bit nodenums this will be shortend on the target"""
|
||||
|
||||
BROADCAST_ADDR = "^all"
|
||||
"""A special ID that means broadcast"""
|
||||
|
||||
OUR_APP_VERSION = 20200
|
||||
"""The numeric buildnumber (shared with android apps) specifying the
|
||||
level of device code we are guaranteed to understand
|
||||
|
||||
format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
|
||||
"""
|
||||
|
||||
publishingThread = DeferredExecution("publishing")
|
||||
|
||||
|
||||
class ResponseHandler(NamedTuple):
|
||||
"""A pending response callback, waiting for a response to one of our messages"""
|
||||
# requestId: int - used only as a key
|
||||
callback: Callable
|
||||
# FIXME, add timestamp and age out old requests
|
||||
|
||||
|
||||
class KnownProtocol(NamedTuple):
|
||||
"""Used to automatically decode known protocol payloads"""
|
||||
name: str
|
||||
# portnum: int, now a key
|
||||
# If set, will be called to prase as a protocol buffer
|
||||
protobufFactory: Callable = None
|
||||
# If set, invoked as onReceive(interface, packet)
|
||||
onReceive: Callable = None
|
||||
|
||||
|
||||
def _onTextReceive(iface, asDict):
|
||||
"""Special text auto parsing for received messages"""
|
||||
# We don't throw if the utf8 is invalid in the text message. Instead we just don't populate
|
||||
# the decoded.data.text and we log an error message. This at least allows some delivery to
|
||||
# the app and the app can deal with the missing decoded representation.
|
||||
#
|
||||
# Usually btw this problem is caused by apps sending binary data but setting the payload type to
|
||||
# text.
|
||||
try:
|
||||
asBytes = asDict["decoded"]["payload"]
|
||||
asDict["decoded"]["text"] = asBytes.decode("utf-8")
|
||||
except Exception as ex:
|
||||
logging.error(f"Malformatted utf8 in text message: {ex}")
|
||||
_receiveInfoUpdate(iface, asDict)
|
||||
|
||||
|
||||
def _onPositionReceive(iface, asDict):
|
||||
"""Special auto parsing for received messages"""
|
||||
p = asDict["decoded"]["position"]
|
||||
iface._fixupPosition(p)
|
||||
# update node DB as needed
|
||||
iface._getOrCreateByNum(asDict["from"])["position"] = p
|
||||
|
||||
|
||||
def _onNodeInfoReceive(iface, asDict):
|
||||
"""Special auto parsing for received messages"""
|
||||
p = asDict["decoded"]["user"]
|
||||
# decode user protobufs and update nodedb, provide decoded version as "position" in the published msg
|
||||
# update node DB as needed
|
||||
n = iface._getOrCreateByNum(asDict["from"])
|
||||
n["user"] = p
|
||||
# We now have a node ID, make sure it is uptodate in that table
|
||||
iface.nodes[p["id"]] = n
|
||||
_receiveInfoUpdate(iface, asDict)
|
||||
|
||||
|
||||
def _receiveInfoUpdate(iface, asDict):
|
||||
if "from" in asDict:
|
||||
iface._getOrCreateByNum(asDict["from"])["lastReceived"] = asDict
|
||||
iface._getOrCreateByNum(asDict["from"])["lastHeard"] = asDict.get("rxTime")
|
||||
iface._getOrCreateByNum(asDict["from"])["snr"] = asDict.get("rxSnr")
|
||||
iface._getOrCreateByNum(asDict["from"])["hopLimit"] = asDict.get("hopLimit")
|
||||
|
||||
|
||||
"""Well known message payloads can register decoders for automatic protobuf parsing"""
|
||||
protocols = {
|
||||
portnums_pb2.PortNum.TEXT_MESSAGE_APP: KnownProtocol("text", onReceive=_onTextReceive),
|
||||
portnums_pb2.PortNum.POSITION_APP: KnownProtocol("position", mesh_pb2.Position, _onPositionReceive),
|
||||
portnums_pb2.PortNum.NODEINFO_APP: KnownProtocol("user", mesh_pb2.User, _onNodeInfoReceive),
|
||||
portnums_pb2.PortNum.ADMIN_APP: KnownProtocol("admin", admin_pb2.AdminMessage),
|
||||
portnums_pb2.PortNum.ROUTING_APP: KnownProtocol("routing", mesh_pb2.Routing),
|
||||
portnums_pb2.PortNum.ENVIRONMENTAL_MEASUREMENT_APP: KnownProtocol("environmental", environmental_measurement_pb2.EnvironmentalMeasurement),
|
||||
portnums_pb2.PortNum.REMOTE_HARDWARE_APP: KnownProtocol(
|
||||
"remotehw", remote_hardware_pb2.HardwareMessage)
|
||||
}</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-submodules">Sub-modules</h2>
|
||||
<dl>
|
||||
<dt><code class="name"><a title="meshtastic.admin_pb2" href="admin_pb2.html">meshtastic.admin_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.apponly_pb2" href="apponly_pb2.html">meshtastic.apponly_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.ble" href="ble.html">meshtastic.ble</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.ble_interface" href="ble_interface.html">meshtastic.ble_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Bluetooth interface</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.channel_pb2" href="channel_pb2.html">meshtastic.channel_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.deviceonly_pb2" href="deviceonly_pb2.html">meshtastic.deviceonly_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.environmental_measurement_pb2" href="environmental_measurement_pb2.html">meshtastic.environmental_measurement_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.globals" href="globals.html">meshtastic.globals</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Globals singleton class …</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.mesh_interface" href="mesh_interface.html">meshtastic.mesh_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Mesh Interface class</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.mesh_pb2" href="mesh_pb2.html">meshtastic.mesh_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.mqtt_pb2" href="mqtt_pb2.html">meshtastic.mqtt_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.node" href="node.html">meshtastic.node</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Node class</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.portnums_pb2" href="portnums_pb2.html">meshtastic.portnums_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.radioconfig_pb2" href="radioconfig_pb2.html">meshtastic.radioconfig_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.remote_hardware" href="remote_hardware.html">meshtastic.remote_hardware</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Remote hardware</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.remote_hardware_pb2" href="remote_hardware_pb2.html">meshtastic.remote_hardware_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.serial_interface" href="serial_interface.html">meshtastic.serial_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Serial interface class</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.storeforward_pb2" href="storeforward_pb2.html">meshtastic.storeforward_pb2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.stream_interface" href="stream_interface.html">meshtastic.stream_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Stream Interface base class</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tcp_interface" href="tcp_interface.html">meshtastic.tcp_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>TCPInterface class for interfacing with http endpoint</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.test" href="test.html">meshtastic.test</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>With two radios connected serially, send and receive test
|
||||
messages and report back if successful.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests" href="tests/index.html">meshtastic.tests</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tunnel" href="tunnel.html">meshtastic.tunnel</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Code for IP tunnel over a mesh …</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.util" href="util.html">meshtastic.util</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Utility functions.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-variables">Global variables</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.BROADCAST_ADDR"><code class="name">var <span class="ident">BROADCAST_ADDR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A special ID that means broadcast</p></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.BROADCAST_NUM"><code class="name">var <span class="ident">BROADCAST_NUM</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>if using 8 bit nodenums this will be shortend on the target</p></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.LOCAL_ADDR"><code class="name">var <span class="ident">LOCAL_ADDR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A special ID that means the local node</p></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.OUR_APP_VERSION"><code class="name">var <span class="ident">OUR_APP_VERSION</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>The numeric buildnumber (shared with android apps) specifying the
|
||||
level of device code we are guaranteed to understand</p>
|
||||
<p>format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.KnownProtocol"><code class="flex name class">
|
||||
<span>class <span class="ident">KnownProtocol</span></span>
|
||||
<span>(</span><span>name: str, protobufFactory: Callable = None, onReceive: Callable = None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Used to automatically decode known protocol payloads</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class KnownProtocol(NamedTuple):
|
||||
"""Used to automatically decode known protocol payloads"""
|
||||
name: str
|
||||
# portnum: int, now a key
|
||||
# If set, will be called to prase as a protocol buffer
|
||||
protobufFactory: Callable = None
|
||||
# If set, invoked as onReceive(interface, packet)
|
||||
onReceive: Callable = None</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>builtins.tuple</li>
|
||||
</ul>
|
||||
<h3>Instance variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.KnownProtocol.name"><code class="name">var <span class="ident">name</span> : str</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Alias for field number 0</p></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.KnownProtocol.onReceive"><code class="name">var <span class="ident">onReceive</span> : Callable</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Alias for field number 2</p></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.KnownProtocol.protobufFactory"><code class="name">var <span class="ident">protobufFactory</span> : Callable</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Alias for field number 1</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="meshtastic.ResponseHandler"><code class="flex name class">
|
||||
<span>class <span class="ident">ResponseHandler</span></span>
|
||||
<span>(</span><span>callback: Callable)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A pending response callback, waiting for a response to one of our messages</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class ResponseHandler(NamedTuple):
|
||||
"""A pending response callback, waiting for a response to one of our messages"""
|
||||
# requestId: int - used only as a key
|
||||
callback: Callable
|
||||
# FIXME, add timestamp and age out old requests</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>builtins.tuple</li>
|
||||
</ul>
|
||||
<h3>Instance variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.ResponseHandler.callback"><code class="name">var <span class="ident">callback</span> : Callable</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Alias for field number 0</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul>
|
||||
<li><a href="#an-api-for-meshtastic-devices">an API for Meshtastic devices</a></li>
|
||||
<li><a href="#published-pubsub-topics">Published PubSub topics</a></li>
|
||||
<li><a href="#example-usage">Example Usage</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3><a href="#header-submodules">Sub-modules</a></h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.admin_pb2" href="admin_pb2.html">meshtastic.admin_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.apponly_pb2" href="apponly_pb2.html">meshtastic.apponly_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.ble" href="ble.html">meshtastic.ble</a></code></li>
|
||||
<li><code><a title="meshtastic.ble_interface" href="ble_interface.html">meshtastic.ble_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.channel_pb2" href="channel_pb2.html">meshtastic.channel_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.deviceonly_pb2" href="deviceonly_pb2.html">meshtastic.deviceonly_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.environmental_measurement_pb2" href="environmental_measurement_pb2.html">meshtastic.environmental_measurement_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.globals" href="globals.html">meshtastic.globals</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface" href="mesh_interface.html">meshtastic.mesh_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_pb2" href="mesh_pb2.html">meshtastic.mesh_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2" href="mqtt_pb2.html">meshtastic.mqtt_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.node" href="node.html">meshtastic.node</a></code></li>
|
||||
<li><code><a title="meshtastic.portnums_pb2" href="portnums_pb2.html">meshtastic.portnums_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.radioconfig_pb2" href="radioconfig_pb2.html">meshtastic.radioconfig_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware" href="remote_hardware.html">meshtastic.remote_hardware</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2" href="remote_hardware_pb2.html">meshtastic.remote_hardware_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.serial_interface" href="serial_interface.html">meshtastic.serial_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.storeforward_pb2" href="storeforward_pb2.html">meshtastic.storeforward_pb2</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface" href="stream_interface.html">meshtastic.stream_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.tcp_interface" href="tcp_interface.html">meshtastic.tcp_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.test" href="test.html">meshtastic.test</a></code></li>
|
||||
<li><code><a title="meshtastic.tests" href="tests/index.html">meshtastic.tests</a></code></li>
|
||||
<li><code><a title="meshtastic.tunnel" href="tunnel.html">meshtastic.tunnel</a></code></li>
|
||||
<li><code><a title="meshtastic.util" href="util.html">meshtastic.util</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-variables">Global variables</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.BROADCAST_ADDR" href="#meshtastic.BROADCAST_ADDR">BROADCAST_ADDR</a></code></li>
|
||||
<li><code><a title="meshtastic.BROADCAST_NUM" href="#meshtastic.BROADCAST_NUM">BROADCAST_NUM</a></code></li>
|
||||
<li><code><a title="meshtastic.LOCAL_ADDR" href="#meshtastic.LOCAL_ADDR">LOCAL_ADDR</a></code></li>
|
||||
<li><code><a title="meshtastic.OUR_APP_VERSION" href="#meshtastic.OUR_APP_VERSION">OUR_APP_VERSION</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.KnownProtocol" href="#meshtastic.KnownProtocol">KnownProtocol</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.KnownProtocol.name" href="#meshtastic.KnownProtocol.name">name</a></code></li>
|
||||
<li><code><a title="meshtastic.KnownProtocol.onReceive" href="#meshtastic.KnownProtocol.onReceive">onReceive</a></code></li>
|
||||
<li><code><a title="meshtastic.KnownProtocol.protobufFactory" href="#meshtastic.KnownProtocol.protobufFactory">protobufFactory</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.ResponseHandler" href="#meshtastic.ResponseHandler">ResponseHandler</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.ResponseHandler.callback" href="#meshtastic.ResponseHandler.callback">callback</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
1851
docs/meshtastic/mesh_interface.html
Normal file
1851
docs/meshtastic/mesh_interface.html
Normal file
File diff suppressed because it is too large
Load Diff
9935
docs/meshtastic/mesh_pb2.html
Normal file
9935
docs/meshtastic/mesh_pb2.html
Normal file
File diff suppressed because one or more lines are too long
759
docs/meshtastic/mqtt_pb2.html
Normal file
759
docs/meshtastic/mqtt_pb2.html
Normal file
@@ -0,0 +1,759 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.mqtt_pb2 API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.mqtt_pb2</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: mqtt.proto
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from . import mesh_pb2 as mesh__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='mqtt.proto',
|
||||
package='',
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\023com.geeksville.meshB\nMQTTProtosH\003Z!github.com/meshtastic/gomeshproto',
|
||||
serialized_pb=b'\n\nmqtt.proto\x1a\nmesh.proto\"V\n\x0fServiceEnvelope\x12\x1b\n\x06packet\x18\x01 \x01(\x0b\x32\x0b.MeshPacket\x12\x12\n\nchannel_id\x18\x02 \x01(\t\x12\x12\n\ngateway_id\x18\x03 \x01(\tBF\n\x13\x63om.geeksville.meshB\nMQTTProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
|
||||
,
|
||||
dependencies=[mesh__pb2.DESCRIPTOR,])
|
||||
|
||||
|
||||
|
||||
|
||||
_SERVICEENVELOPE = _descriptor.Descriptor(
|
||||
name='ServiceEnvelope',
|
||||
full_name='ServiceEnvelope',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='packet', full_name='ServiceEnvelope.packet', index=0,
|
||||
number=1, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='channel_id', full_name='ServiceEnvelope.channel_id', index=1,
|
||||
number=2, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='gateway_id', full_name='ServiceEnvelope.gateway_id', index=2,
|
||||
number=3, type=9, cpp_type=9, label=1,
|
||||
has_default_value=False, default_value=b"".decode('utf-8'),
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=26,
|
||||
serialized_end=112,
|
||||
)
|
||||
|
||||
_SERVICEENVELOPE.fields_by_name['packet'].message_type = mesh__pb2._MESHPACKET
|
||||
DESCRIPTOR.message_types_by_name['ServiceEnvelope'] = _SERVICEENVELOPE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
ServiceEnvelope = _reflection.GeneratedProtocolMessageType('ServiceEnvelope', (_message.Message,), {
|
||||
'DESCRIPTOR' : _SERVICEENVELOPE,
|
||||
'__module__' : 'mqtt_pb2'
|
||||
# @@protoc_insertion_point(class_scope:ServiceEnvelope)
|
||||
})
|
||||
_sym_db.RegisterMessage(ServiceEnvelope)
|
||||
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope"><code class="flex name class">
|
||||
<span>class <span class="ident">ServiceEnvelope</span></span>
|
||||
<span>(</span><span>**kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Abstract base class for protocol messages.</p>
|
||||
<p>Protocol message classes are almost always generated by the protocol
|
||||
compiler.
|
||||
These generated types subclass Message and implement the methods
|
||||
shown below.</p></div>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>google.protobuf.message.Message</li>
|
||||
</ul>
|
||||
<h3>Class variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.CHANNEL_ID_FIELD_NUMBER"><code class="name">var <span class="ident">CHANNEL_ID_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.GATEWAY_ID_FIELD_NUMBER"><code class="name">var <span class="ident">GATEWAY_ID_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.PACKET_FIELD_NUMBER"><code class="name">var <span class="ident">PACKET_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Static methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.FromString"><code class="name flex">
|
||||
<span>def <span class="ident">FromString</span></span>(<span>s)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def FromString(s):
|
||||
message = cls()
|
||||
message.MergeFromString(s)
|
||||
return message</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.RegisterExtension"><code class="name flex">
|
||||
<span>def <span class="ident">RegisterExtension</span></span>(<span>extension_handle)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def RegisterExtension(extension_handle):
|
||||
extension_handle.containing_type = cls.DESCRIPTOR
|
||||
# TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
|
||||
# pylint: disable=protected-access
|
||||
cls.DESCRIPTOR.file.pool._AddExtensionDescriptor(extension_handle)
|
||||
_AttachFieldHelpers(cls, extension_handle)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Instance variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.channel_id"><code class="name">var <span class="ident">channel_id</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for channel_id.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
# TODO(protobuf-team): This may be broken since there may not be
|
||||
# default_value. Combine with has_default_value somehow.
|
||||
return self._fields.get(field, default_value)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.gateway_id"><code class="name">var <span class="ident">gateway_id</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for gateway_id.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
# TODO(protobuf-team): This may be broken since there may not be
|
||||
# default_value. Combine with has_default_value somehow.
|
||||
return self._fields.get(field, default_value)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.packet"><code class="name">var <span class="ident">packet</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for packet.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
field_value = self._fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
|
||||
# Atomically check if another thread has preempted us and, if not, swap
|
||||
# in the new object we just created. If someone has preempted us, we
|
||||
# take that object and discard ours.
|
||||
# WARNING: We are relying on setdefault() being atomic. This is true
|
||||
# in CPython but we haven't investigated others. This warning appears
|
||||
# in several other locations in this file.
|
||||
field_value = self._fields.setdefault(field, field_value)
|
||||
return field_value</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.ByteSize"><code class="name flex">
|
||||
<span>def <span class="ident">ByteSize</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ByteSize(self):
|
||||
if not self._cached_byte_size_dirty:
|
||||
return self._cached_byte_size
|
||||
|
||||
size = 0
|
||||
descriptor = self.DESCRIPTOR
|
||||
if descriptor.GetOptions().map_entry:
|
||||
# Fields of map entry should always be serialized.
|
||||
size = descriptor.fields_by_name['key']._sizer(self.key)
|
||||
size += descriptor.fields_by_name['value']._sizer(self.value)
|
||||
else:
|
||||
for field_descriptor, field_value in self.ListFields():
|
||||
size += field_descriptor._sizer(field_value)
|
||||
for tag_bytes, value_bytes in self._unknown_fields:
|
||||
size += len(tag_bytes) + len(value_bytes)
|
||||
|
||||
self._cached_byte_size = size
|
||||
self._cached_byte_size_dirty = False
|
||||
self._listener_for_children.dirty = False
|
||||
return size</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.Clear"><code class="name flex">
|
||||
<span>def <span class="ident">Clear</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _Clear(self):
|
||||
# Clear fields.
|
||||
self._fields = {}
|
||||
self._unknown_fields = ()
|
||||
# pylint: disable=protected-access
|
||||
if self._unknown_field_set is not None:
|
||||
self._unknown_field_set._clear()
|
||||
self._unknown_field_set = None
|
||||
|
||||
self._oneofs = {}
|
||||
self._Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.ClearField"><code class="name flex">
|
||||
<span>def <span class="ident">ClearField</span></span>(<span>self, field_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ClearField(self, field_name):
|
||||
try:
|
||||
field = message_descriptor.fields_by_name[field_name]
|
||||
except KeyError:
|
||||
try:
|
||||
field = message_descriptor.oneofs_by_name[field_name]
|
||||
if field in self._oneofs:
|
||||
field = self._oneofs[field]
|
||||
else:
|
||||
return
|
||||
except KeyError:
|
||||
raise ValueError('Protocol message %s has no "%s" field.' %
|
||||
(message_descriptor.name, field_name))
|
||||
|
||||
if field in self._fields:
|
||||
# To match the C++ implementation, we need to invalidate iterators
|
||||
# for map fields when ClearField() happens.
|
||||
if hasattr(self._fields[field], 'InvalidateIterators'):
|
||||
self._fields[field].InvalidateIterators()
|
||||
|
||||
# Note: If the field is a sub-message, its listener will still point
|
||||
# at us. That's fine, because the worst than can happen is that it
|
||||
# will call _Modified() and invalidate our byte size. Big deal.
|
||||
del self._fields[field]
|
||||
|
||||
if self._oneofs.get(field.containing_oneof, None) is field:
|
||||
del self._oneofs[field.containing_oneof]
|
||||
|
||||
# Always call _Modified() -- even if nothing was changed, this is
|
||||
# a mutating method, and thus calling it should cause the field to become
|
||||
# present in the parent message.
|
||||
self._Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.DiscardUnknownFields"><code class="name flex">
|
||||
<span>def <span class="ident">DiscardUnknownFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _DiscardUnknownFields(self):
|
||||
self._unknown_fields = []
|
||||
self._unknown_field_set = None # pylint: disable=protected-access
|
||||
for field, value in self.ListFields():
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if _IsMapField(field):
|
||||
if _IsMessageMapField(field):
|
||||
for key in value:
|
||||
value[key].DiscardUnknownFields()
|
||||
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
for sub_message in value:
|
||||
sub_message.DiscardUnknownFields()
|
||||
else:
|
||||
value.DiscardUnknownFields()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.FindInitializationErrors"><code class="name flex">
|
||||
<span>def <span class="ident">FindInitializationErrors</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Finds required fields which are not initialized.</p>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>A list of strings.
|
||||
Each string is a path to an uninitialized field from
|
||||
the top-level message, e.g. "foo.bar[5].baz".</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def FindInitializationErrors(self):
|
||||
"""Finds required fields which are not initialized.
|
||||
|
||||
Returns:
|
||||
A list of strings. Each string is a path to an uninitialized field from
|
||||
the top-level message, e.g. "foo.bar[5].baz".
|
||||
"""
|
||||
|
||||
errors = [] # simplify things
|
||||
|
||||
for field in required_fields:
|
||||
if not self.HasField(field.name):
|
||||
errors.append(field.name)
|
||||
|
||||
for field, value in self.ListFields():
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if field.is_extension:
|
||||
name = '(%s)' % field.full_name
|
||||
else:
|
||||
name = field.name
|
||||
|
||||
if _IsMapField(field):
|
||||
if _IsMessageMapField(field):
|
||||
for key in value:
|
||||
element = value[key]
|
||||
prefix = '%s[%s].' % (name, key)
|
||||
sub_errors = element.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
else:
|
||||
# ScalarMaps can't have any initialization errors.
|
||||
pass
|
||||
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
for i in range(len(value)):
|
||||
element = value[i]
|
||||
prefix = '%s[%d].' % (name, i)
|
||||
sub_errors = element.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
else:
|
||||
prefix = name + '.'
|
||||
sub_errors = value.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
|
||||
return errors</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.HasField"><code class="name flex">
|
||||
<span>def <span class="ident">HasField</span></span>(<span>self, field_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def HasField(self, field_name):
|
||||
try:
|
||||
field = hassable_fields[field_name]
|
||||
except KeyError:
|
||||
raise ValueError(error_msg % (message_descriptor.full_name, field_name))
|
||||
|
||||
if isinstance(field, descriptor_mod.OneofDescriptor):
|
||||
try:
|
||||
return HasField(self, self._oneofs[field].name)
|
||||
except KeyError:
|
||||
return False
|
||||
else:
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
value = self._fields.get(field)
|
||||
return value is not None and value._is_present_in_parent
|
||||
else:
|
||||
return field in self._fields</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.IsInitialized"><code class="name flex">
|
||||
<span>def <span class="ident">IsInitialized</span></span>(<span>self, errors=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Checks if all required fields of a message are set.</p>
|
||||
<h2 id="args">Args</h2>
|
||||
<dl>
|
||||
<dt><strong><code>errors</code></strong></dt>
|
||||
<dd>A list which, if provided, will be populated with the field
|
||||
paths of all missing required fields.</dd>
|
||||
</dl>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>True iff the specified message has all required fields set.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def IsInitialized(self, errors=None):
|
||||
"""Checks if all required fields of a message are set.
|
||||
|
||||
Args:
|
||||
errors: A list which, if provided, will be populated with the field
|
||||
paths of all missing required fields.
|
||||
|
||||
Returns:
|
||||
True iff the specified message has all required fields set.
|
||||
"""
|
||||
|
||||
# Performance is critical so we avoid HasField() and ListFields().
|
||||
|
||||
for field in required_fields:
|
||||
if (field not in self._fields or
|
||||
(field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
|
||||
not self._fields[field]._is_present_in_parent)):
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
|
||||
for field, value in list(self._fields.items()): # dict can change size!
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
if (field.message_type.has_options and
|
||||
field.message_type.GetOptions().map_entry):
|
||||
continue
|
||||
for element in value:
|
||||
if not element.IsInitialized():
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
elif value._is_present_in_parent and not value.IsInitialized():
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
|
||||
return True</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.ListFields"><code class="name flex">
|
||||
<span>def <span class="ident">ListFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ListFields(self):
|
||||
all_fields = [item for item in self._fields.items() if _IsPresent(item)]
|
||||
all_fields.sort(key = lambda item: item[0].number)
|
||||
return all_fields</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.MergeFrom"><code class="name flex">
|
||||
<span>def <span class="ident">MergeFrom</span></span>(<span>self, msg)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def MergeFrom(self, msg):
|
||||
if not isinstance(msg, cls):
|
||||
raise TypeError(
|
||||
'Parameter to MergeFrom() must be instance of same class: '
|
||||
'expected %s got %s.' % (_FullyQualifiedClassName(cls),
|
||||
_FullyQualifiedClassName(msg.__class__)))
|
||||
|
||||
assert msg is not self
|
||||
self._Modified()
|
||||
|
||||
fields = self._fields
|
||||
|
||||
for field, value in msg._fields.items():
|
||||
if field.label == LABEL_REPEATED:
|
||||
field_value = fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
fields[field] = field_value
|
||||
field_value.MergeFrom(value)
|
||||
elif field.cpp_type == CPPTYPE_MESSAGE:
|
||||
if value._is_present_in_parent:
|
||||
field_value = fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
fields[field] = field_value
|
||||
field_value.MergeFrom(value)
|
||||
else:
|
||||
self._fields[field] = value
|
||||
if field.containing_oneof:
|
||||
self._UpdateOneofState(field)
|
||||
|
||||
if msg._unknown_fields:
|
||||
if not self._unknown_fields:
|
||||
self._unknown_fields = []
|
||||
self._unknown_fields.extend(msg._unknown_fields)
|
||||
# pylint: disable=protected-access
|
||||
if self._unknown_field_set is None:
|
||||
self._unknown_field_set = containers.UnknownFieldSet()
|
||||
self._unknown_field_set._extend(msg._unknown_field_set)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.MergeFromString"><code class="name flex">
|
||||
<span>def <span class="ident">MergeFromString</span></span>(<span>self, serialized)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def MergeFromString(self, serialized):
|
||||
serialized = memoryview(serialized)
|
||||
length = len(serialized)
|
||||
try:
|
||||
if self._InternalParse(serialized, 0, length) != length:
|
||||
# The only reason _InternalParse would return early is if it
|
||||
# encountered an end-group tag.
|
||||
raise message_mod.DecodeError('Unexpected end-group tag.')
|
||||
except (IndexError, TypeError):
|
||||
# Now ord(buf[p:p+1]) == ord('') gets TypeError.
|
||||
raise message_mod.DecodeError('Truncated message.')
|
||||
except struct.error as e:
|
||||
raise message_mod.DecodeError(e)
|
||||
return length # Return this for legacy reasons.</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.SerializePartialToString"><code class="name flex">
|
||||
<span>def <span class="ident">SerializePartialToString</span></span>(<span>self, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def SerializePartialToString(self, **kwargs):
|
||||
out = BytesIO()
|
||||
self._InternalSerialize(out.write, **kwargs)
|
||||
return out.getvalue()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.SerializeToString"><code class="name flex">
|
||||
<span>def <span class="ident">SerializeToString</span></span>(<span>self, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def SerializeToString(self, **kwargs):
|
||||
# Check if the message has all of its required fields set.
|
||||
if not self.IsInitialized():
|
||||
raise message_mod.EncodeError(
|
||||
'Message %s is missing required fields: %s' % (
|
||||
self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
|
||||
return self.SerializePartialToString(**kwargs)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.SetInParent"><code class="name flex">
|
||||
<span>def <span class="ident">SetInParent</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Sets the _cached_byte_size_dirty bit to true,
|
||||
and propagates this to our listener iff this was a state change.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def Modified(self):
|
||||
"""Sets the _cached_byte_size_dirty bit to true,
|
||||
and propagates this to our listener iff this was a state change.
|
||||
"""
|
||||
|
||||
# Note: Some callers check _cached_byte_size_dirty before calling
|
||||
# _Modified() as an extra optimization. So, if this method is ever
|
||||
# changed such that it does stuff even when _cached_byte_size_dirty is
|
||||
# already true, the callers need to be updated.
|
||||
if not self._cached_byte_size_dirty:
|
||||
self._cached_byte_size_dirty = True
|
||||
self._listener_for_children.dirty = True
|
||||
self._is_present_in_parent = True
|
||||
self._listener.Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.UnknownFields"><code class="name flex">
|
||||
<span>def <span class="ident">UnknownFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _UnknownFields(self):
|
||||
if self._unknown_field_set is None: # pylint: disable=protected-access
|
||||
# pylint: disable=protected-access
|
||||
self._unknown_field_set = containers.UnknownFieldSet()
|
||||
return self._unknown_field_set # pylint: disable=protected-access</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.mqtt_pb2.ServiceEnvelope.WhichOneof"><code class="name flex">
|
||||
<span>def <span class="ident">WhichOneof</span></span>(<span>self, oneof_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Returns the name of the currently set field inside a oneof, or None.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def WhichOneof(self, oneof_name):
|
||||
"""Returns the name of the currently set field inside a oneof, or None."""
|
||||
try:
|
||||
field = message_descriptor.oneofs_by_name[oneof_name]
|
||||
except KeyError:
|
||||
raise ValueError(
|
||||
'Protocol message has no oneof "%s" field.' % oneof_name)
|
||||
|
||||
nested_field = self._oneofs.get(field, None)
|
||||
if nested_field is not None and self.HasField(nested_field.name):
|
||||
return nested_field.name
|
||||
else:
|
||||
return None</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope" href="#meshtastic.mqtt_pb2.ServiceEnvelope">ServiceEnvelope</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.ByteSize" href="#meshtastic.mqtt_pb2.ServiceEnvelope.ByteSize">ByteSize</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.CHANNEL_ID_FIELD_NUMBER" href="#meshtastic.mqtt_pb2.ServiceEnvelope.CHANNEL_ID_FIELD_NUMBER">CHANNEL_ID_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.Clear" href="#meshtastic.mqtt_pb2.ServiceEnvelope.Clear">Clear</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.ClearField" href="#meshtastic.mqtt_pb2.ServiceEnvelope.ClearField">ClearField</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.DESCRIPTOR" href="#meshtastic.mqtt_pb2.ServiceEnvelope.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.DiscardUnknownFields" href="#meshtastic.mqtt_pb2.ServiceEnvelope.DiscardUnknownFields">DiscardUnknownFields</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.FindInitializationErrors" href="#meshtastic.mqtt_pb2.ServiceEnvelope.FindInitializationErrors">FindInitializationErrors</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.FromString" href="#meshtastic.mqtt_pb2.ServiceEnvelope.FromString">FromString</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.GATEWAY_ID_FIELD_NUMBER" href="#meshtastic.mqtt_pb2.ServiceEnvelope.GATEWAY_ID_FIELD_NUMBER">GATEWAY_ID_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.HasField" href="#meshtastic.mqtt_pb2.ServiceEnvelope.HasField">HasField</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.IsInitialized" href="#meshtastic.mqtt_pb2.ServiceEnvelope.IsInitialized">IsInitialized</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.ListFields" href="#meshtastic.mqtt_pb2.ServiceEnvelope.ListFields">ListFields</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.MergeFrom" href="#meshtastic.mqtt_pb2.ServiceEnvelope.MergeFrom">MergeFrom</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.MergeFromString" href="#meshtastic.mqtt_pb2.ServiceEnvelope.MergeFromString">MergeFromString</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.PACKET_FIELD_NUMBER" href="#meshtastic.mqtt_pb2.ServiceEnvelope.PACKET_FIELD_NUMBER">PACKET_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.RegisterExtension" href="#meshtastic.mqtt_pb2.ServiceEnvelope.RegisterExtension">RegisterExtension</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.SerializePartialToString" href="#meshtastic.mqtt_pb2.ServiceEnvelope.SerializePartialToString">SerializePartialToString</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.SerializeToString" href="#meshtastic.mqtt_pb2.ServiceEnvelope.SerializeToString">SerializeToString</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.SetInParent" href="#meshtastic.mqtt_pb2.ServiceEnvelope.SetInParent">SetInParent</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.UnknownFields" href="#meshtastic.mqtt_pb2.ServiceEnvelope.UnknownFields">UnknownFields</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.WhichOneof" href="#meshtastic.mqtt_pb2.ServiceEnvelope.WhichOneof">WhichOneof</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.channel_id" href="#meshtastic.mqtt_pb2.ServiceEnvelope.channel_id">channel_id</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.gateway_id" href="#meshtastic.mqtt_pb2.ServiceEnvelope.gateway_id">gateway_id</a></code></li>
|
||||
<li><code><a title="meshtastic.mqtt_pb2.ServiceEnvelope.packet" href="#meshtastic.mqtt_pb2.ServiceEnvelope.packet">packet</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
1280
docs/meshtastic/node.html
Normal file
1280
docs/meshtastic/node.html
Normal file
File diff suppressed because it is too large
Load Diff
190
docs/meshtastic/portnums_pb2.html
Normal file
190
docs/meshtastic/portnums_pb2.html
Normal file
@@ -0,0 +1,190 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.portnums_pb2 API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.portnums_pb2</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: portnums.proto
|
||||
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='portnums.proto',
|
||||
package='',
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\023com.geeksville.meshB\010PortnumsH\003Z!github.com/meshtastic/gomeshproto',
|
||||
serialized_pb=b'\n\x0eportnums.proto*\xcb\x02\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12!\n\x1d\x45NVIRONMENTAL_MEASUREMENT_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x10\n\x0bPRIVATE_APP\x10\x80\x02\x12\x13\n\x0e\x41TAK_FORWARDER\x10\x81\x02\x12\x08\n\x03MAX\x10\xff\x03\x42\x44\n\x13\x63om.geeksville.meshB\x08PortnumsH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
|
||||
)
|
||||
|
||||
_PORTNUM = _descriptor.EnumDescriptor(
|
||||
name='PortNum',
|
||||
full_name='PortNum',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UNKNOWN_APP', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='TEXT_MESSAGE_APP', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='REMOTE_HARDWARE_APP', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='POSITION_APP', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='NODEINFO_APP', index=4, number=4,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ROUTING_APP', index=5, number=5,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ADMIN_APP', index=6, number=6,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='REPLY_APP', index=7, number=32,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='IP_TUNNEL_APP', index=8, number=33,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='SERIAL_APP', index=9, number=64,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='STORE_FORWARD_APP', index=10, number=65,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='RANGE_TEST_APP', index=11, number=66,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ENVIRONMENTAL_MEASUREMENT_APP', index=12, number=67,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ZPS_APP', index=13, number=68,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='PRIVATE_APP', index=14, number=256,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='ATAK_FORWARDER', index=15, number=257,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='MAX', index=16, number=511,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=19,
|
||||
serialized_end=350,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_PORTNUM)
|
||||
|
||||
PortNum = enum_type_wrapper.EnumTypeWrapper(_PORTNUM)
|
||||
UNKNOWN_APP = 0
|
||||
TEXT_MESSAGE_APP = 1
|
||||
REMOTE_HARDWARE_APP = 2
|
||||
POSITION_APP = 3
|
||||
NODEINFO_APP = 4
|
||||
ROUTING_APP = 5
|
||||
ADMIN_APP = 6
|
||||
REPLY_APP = 32
|
||||
IP_TUNNEL_APP = 33
|
||||
SERIAL_APP = 64
|
||||
STORE_FORWARD_APP = 65
|
||||
RANGE_TEST_APP = 66
|
||||
ENVIRONMENTAL_MEASUREMENT_APP = 67
|
||||
ZPS_APP = 68
|
||||
PRIVATE_APP = 256
|
||||
ATAK_FORWARDER = 257
|
||||
MAX = 511
|
||||
|
||||
|
||||
DESCRIPTOR.enum_types_by_name['PortNum'] = _PORTNUM
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
1604
docs/meshtastic/radioconfig_pb2.html
Normal file
1604
docs/meshtastic/radioconfig_pb2.html
Normal file
File diff suppressed because one or more lines are too long
324
docs/meshtastic/remote_hardware.html
Normal file
324
docs/meshtastic/remote_hardware.html
Normal file
@@ -0,0 +1,324 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.remote_hardware API documentation</title>
|
||||
<meta name="description" content="Remote hardware" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.remote_hardware</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Remote hardware</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Remote hardware
|
||||
"""
|
||||
import logging
|
||||
from pubsub import pub
|
||||
from . import portnums_pb2, remote_hardware_pb2
|
||||
from .util import our_exit
|
||||
|
||||
|
||||
def onGPIOreceive(packet, interface):
|
||||
"""Callback for received GPIO responses
|
||||
"""
|
||||
logging.debug(f"packet:{packet} interface:{interface}")
|
||||
hw = packet["decoded"]["remotehw"]
|
||||
gpioValue = hw["gpioValue"]
|
||||
#print(f'mask:{interface.mask}')
|
||||
value = int(gpioValue) & int(interface.mask)
|
||||
print(f'Received RemoteHardware typ={hw["typ"]}, gpio_value={gpioValue} value={value}')
|
||||
interface.gotResponse = True
|
||||
|
||||
|
||||
class RemoteHardwareClient:
|
||||
"""
|
||||
This is the client code to control/monitor simple hardware built into the
|
||||
meshtastic devices. It is intended to be both a useful API/service and example
|
||||
code for how you can connect to your own custom meshtastic services
|
||||
"""
|
||||
|
||||
def __init__(self, iface):
|
||||
"""
|
||||
Constructor
|
||||
|
||||
iface is the already open MeshInterface instance
|
||||
"""
|
||||
self.iface = iface
|
||||
ch = iface.localNode.getChannelByName("gpio")
|
||||
if not ch:
|
||||
our_exit(
|
||||
"Warning: No channel named 'gpio' was found.\n"\
|
||||
"On the sending and receive nodes create a channel named 'gpio'.\n"\
|
||||
"For example, run '--ch-add gpio' on one device, then '--seturl' on\n"\
|
||||
"the other devices using the url from the device where the channel was added.")
|
||||
self.channelIndex = ch.index
|
||||
|
||||
pub.subscribe(onGPIOreceive, "meshtastic.receive.remotehw")
|
||||
|
||||
def _sendHardware(self, nodeid, r, wantResponse=False, onResponse=None):
|
||||
if not nodeid:
|
||||
our_exit(r"Warning: Must use a destination node ID for this operation (use --dest \!xxxxxxxxx)")
|
||||
return self.iface.sendData(r, nodeid, portnums_pb2.REMOTE_HARDWARE_APP,
|
||||
wantAck=True, channelIndex=self.channelIndex,
|
||||
wantResponse=wantResponse, onResponse=onResponse)
|
||||
|
||||
def writeGPIOs(self, nodeid, mask, vals):
|
||||
"""
|
||||
Write the specified vals bits to the device GPIOs. Only bits in mask that
|
||||
are 1 will be changed
|
||||
"""
|
||||
logging.debug(f'writeGPIOs nodeid:{nodeid} mask:{mask} vals:{vals}')
|
||||
r = remote_hardware_pb2.HardwareMessage()
|
||||
r.typ = remote_hardware_pb2.HardwareMessage.Type.WRITE_GPIOS
|
||||
r.gpio_mask = mask
|
||||
r.gpio_value = vals
|
||||
return self._sendHardware(nodeid, r)
|
||||
|
||||
def readGPIOs(self, nodeid, mask, onResponse = None):
|
||||
"""Read the specified bits from GPIO inputs on the device"""
|
||||
logging.debug(f'readGPIOs nodeid:{nodeid} mask:{mask}')
|
||||
r = remote_hardware_pb2.HardwareMessage()
|
||||
r.typ = remote_hardware_pb2.HardwareMessage.Type.READ_GPIOS
|
||||
r.gpio_mask = mask
|
||||
return self._sendHardware(nodeid, r, wantResponse=True, onResponse=onResponse)
|
||||
|
||||
def watchGPIOs(self, nodeid, mask):
|
||||
"""Watch the specified bits from GPIO inputs on the device for changes"""
|
||||
logging.debug(f'watchGPIOs nodeid:{nodeid} mask:{mask}')
|
||||
r = remote_hardware_pb2.HardwareMessage()
|
||||
r.typ = remote_hardware_pb2.HardwareMessage.Type.WATCH_GPIOS
|
||||
r.gpio_mask = mask
|
||||
self.iface.mask = mask
|
||||
return self._sendHardware(nodeid, r)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.remote_hardware.onGPIOreceive"><code class="name flex">
|
||||
<span>def <span class="ident">onGPIOreceive</span></span>(<span>packet, interface)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Callback for received GPIO responses</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def onGPIOreceive(packet, interface):
|
||||
"""Callback for received GPIO responses
|
||||
"""
|
||||
logging.debug(f"packet:{packet} interface:{interface}")
|
||||
hw = packet["decoded"]["remotehw"]
|
||||
gpioValue = hw["gpioValue"]
|
||||
#print(f'mask:{interface.mask}')
|
||||
value = int(gpioValue) & int(interface.mask)
|
||||
print(f'Received RemoteHardware typ={hw["typ"]}, gpio_value={gpioValue} value={value}')
|
||||
interface.gotResponse = True</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.remote_hardware.RemoteHardwareClient"><code class="flex name class">
|
||||
<span>class <span class="ident">RemoteHardwareClient</span></span>
|
||||
<span>(</span><span>iface)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>This is the client code to control/monitor simple hardware built into the
|
||||
meshtastic devices.
|
||||
It is intended to be both a useful API/service and example
|
||||
code for how you can connect to your own custom meshtastic services</p>
|
||||
<p>Constructor</p>
|
||||
<p>iface is the already open MeshInterface instance</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class RemoteHardwareClient:
|
||||
"""
|
||||
This is the client code to control/monitor simple hardware built into the
|
||||
meshtastic devices. It is intended to be both a useful API/service and example
|
||||
code for how you can connect to your own custom meshtastic services
|
||||
"""
|
||||
|
||||
def __init__(self, iface):
|
||||
"""
|
||||
Constructor
|
||||
|
||||
iface is the already open MeshInterface instance
|
||||
"""
|
||||
self.iface = iface
|
||||
ch = iface.localNode.getChannelByName("gpio")
|
||||
if not ch:
|
||||
our_exit(
|
||||
"Warning: No channel named 'gpio' was found.\n"\
|
||||
"On the sending and receive nodes create a channel named 'gpio'.\n"\
|
||||
"For example, run '--ch-add gpio' on one device, then '--seturl' on\n"\
|
||||
"the other devices using the url from the device where the channel was added.")
|
||||
self.channelIndex = ch.index
|
||||
|
||||
pub.subscribe(onGPIOreceive, "meshtastic.receive.remotehw")
|
||||
|
||||
def _sendHardware(self, nodeid, r, wantResponse=False, onResponse=None):
|
||||
if not nodeid:
|
||||
our_exit(r"Warning: Must use a destination node ID for this operation (use --dest \!xxxxxxxxx)")
|
||||
return self.iface.sendData(r, nodeid, portnums_pb2.REMOTE_HARDWARE_APP,
|
||||
wantAck=True, channelIndex=self.channelIndex,
|
||||
wantResponse=wantResponse, onResponse=onResponse)
|
||||
|
||||
def writeGPIOs(self, nodeid, mask, vals):
|
||||
"""
|
||||
Write the specified vals bits to the device GPIOs. Only bits in mask that
|
||||
are 1 will be changed
|
||||
"""
|
||||
logging.debug(f'writeGPIOs nodeid:{nodeid} mask:{mask} vals:{vals}')
|
||||
r = remote_hardware_pb2.HardwareMessage()
|
||||
r.typ = remote_hardware_pb2.HardwareMessage.Type.WRITE_GPIOS
|
||||
r.gpio_mask = mask
|
||||
r.gpio_value = vals
|
||||
return self._sendHardware(nodeid, r)
|
||||
|
||||
def readGPIOs(self, nodeid, mask, onResponse = None):
|
||||
"""Read the specified bits from GPIO inputs on the device"""
|
||||
logging.debug(f'readGPIOs nodeid:{nodeid} mask:{mask}')
|
||||
r = remote_hardware_pb2.HardwareMessage()
|
||||
r.typ = remote_hardware_pb2.HardwareMessage.Type.READ_GPIOS
|
||||
r.gpio_mask = mask
|
||||
return self._sendHardware(nodeid, r, wantResponse=True, onResponse=onResponse)
|
||||
|
||||
def watchGPIOs(self, nodeid, mask):
|
||||
"""Watch the specified bits from GPIO inputs on the device for changes"""
|
||||
logging.debug(f'watchGPIOs nodeid:{nodeid} mask:{mask}')
|
||||
r = remote_hardware_pb2.HardwareMessage()
|
||||
r.typ = remote_hardware_pb2.HardwareMessage.Type.WATCH_GPIOS
|
||||
r.gpio_mask = mask
|
||||
self.iface.mask = mask
|
||||
return self._sendHardware(nodeid, r)</code></pre>
|
||||
</details>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.remote_hardware.RemoteHardwareClient.readGPIOs"><code class="name flex">
|
||||
<span>def <span class="ident">readGPIOs</span></span>(<span>self, nodeid, mask, onResponse=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Read the specified bits from GPIO inputs on the device</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def readGPIOs(self, nodeid, mask, onResponse = None):
|
||||
"""Read the specified bits from GPIO inputs on the device"""
|
||||
logging.debug(f'readGPIOs nodeid:{nodeid} mask:{mask}')
|
||||
r = remote_hardware_pb2.HardwareMessage()
|
||||
r.typ = remote_hardware_pb2.HardwareMessage.Type.READ_GPIOS
|
||||
r.gpio_mask = mask
|
||||
return self._sendHardware(nodeid, r, wantResponse=True, onResponse=onResponse)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware.RemoteHardwareClient.watchGPIOs"><code class="name flex">
|
||||
<span>def <span class="ident">watchGPIOs</span></span>(<span>self, nodeid, mask)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Watch the specified bits from GPIO inputs on the device for changes</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def watchGPIOs(self, nodeid, mask):
|
||||
"""Watch the specified bits from GPIO inputs on the device for changes"""
|
||||
logging.debug(f'watchGPIOs nodeid:{nodeid} mask:{mask}')
|
||||
r = remote_hardware_pb2.HardwareMessage()
|
||||
r.typ = remote_hardware_pb2.HardwareMessage.Type.WATCH_GPIOS
|
||||
r.gpio_mask = mask
|
||||
self.iface.mask = mask
|
||||
return self._sendHardware(nodeid, r)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware.RemoteHardwareClient.writeGPIOs"><code class="name flex">
|
||||
<span>def <span class="ident">writeGPIOs</span></span>(<span>self, nodeid, mask, vals)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Write the specified vals bits to the device GPIOs.
|
||||
Only bits in mask that
|
||||
are 1 will be changed</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def writeGPIOs(self, nodeid, mask, vals):
|
||||
"""
|
||||
Write the specified vals bits to the device GPIOs. Only bits in mask that
|
||||
are 1 will be changed
|
||||
"""
|
||||
logging.debug(f'writeGPIOs nodeid:{nodeid} mask:{mask} vals:{vals}')
|
||||
r = remote_hardware_pb2.HardwareMessage()
|
||||
r.typ = remote_hardware_pb2.HardwareMessage.Type.WRITE_GPIOS
|
||||
r.gpio_mask = mask
|
||||
r.gpio_value = vals
|
||||
return self._sendHardware(nodeid, r)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.remote_hardware.onGPIOreceive" href="#meshtastic.remote_hardware.onGPIOreceive">onGPIOreceive</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.remote_hardware.RemoteHardwareClient" href="#meshtastic.remote_hardware.RemoteHardwareClient">RemoteHardwareClient</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.remote_hardware.RemoteHardwareClient.readGPIOs" href="#meshtastic.remote_hardware.RemoteHardwareClient.readGPIOs">readGPIOs</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware.RemoteHardwareClient.watchGPIOs" href="#meshtastic.remote_hardware.RemoteHardwareClient.watchGPIOs">watchGPIOs</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware.RemoteHardwareClient.writeGPIOs" href="#meshtastic.remote_hardware.RemoteHardwareClient.writeGPIOs">writeGPIOs</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
822
docs/meshtastic/remote_hardware_pb2.html
Normal file
822
docs/meshtastic/remote_hardware_pb2.html
Normal file
@@ -0,0 +1,822 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.remote_hardware_pb2 API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.remote_hardware_pb2</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python"># -*- coding: utf-8 -*-
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: remote_hardware.proto
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
name='remote_hardware.proto',
|
||||
package='',
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\023com.geeksville.meshB\016RemoteHardwareH\003Z!github.com/meshtastic/gomeshproto',
|
||||
serialized_pb=b'\n\x15remote_hardware.proto\"\xca\x01\n\x0fHardwareMessage\x12\"\n\x03typ\x18\x01 \x01(\x0e\x32\x15.HardwareMessage.Type\x12\x11\n\tgpio_mask\x18\x02 \x01(\x04\x12\x12\n\ngpio_value\x18\x03 \x01(\x04\"l\n\x04Type\x12\t\n\x05UNSET\x10\x00\x12\x0f\n\x0bWRITE_GPIOS\x10\x01\x12\x0f\n\x0bWATCH_GPIOS\x10\x02\x12\x11\n\rGPIOS_CHANGED\x10\x03\x12\x0e\n\nREAD_GPIOS\x10\x04\x12\x14\n\x10READ_GPIOS_REPLY\x10\x05\x42J\n\x13\x63om.geeksville.meshB\x0eRemoteHardwareH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
|
||||
)
|
||||
|
||||
|
||||
|
||||
_HARDWAREMESSAGE_TYPE = _descriptor.EnumDescriptor(
|
||||
name='Type',
|
||||
full_name='HardwareMessage.Type',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
values=[
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='UNSET', index=0, number=0,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='WRITE_GPIOS', index=1, number=1,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='WATCH_GPIOS', index=2, number=2,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='GPIOS_CHANGED', index=3, number=3,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='READ_GPIOS', index=4, number=4,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='READ_GPIOS_REPLY', index=5, number=5,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=120,
|
||||
serialized_end=228,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_HARDWAREMESSAGE_TYPE)
|
||||
|
||||
|
||||
_HARDWAREMESSAGE = _descriptor.Descriptor(
|
||||
name='HardwareMessage',
|
||||
full_name='HardwareMessage',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='typ', full_name='HardwareMessage.typ', index=0,
|
||||
number=1, type=14, cpp_type=8, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='gpio_mask', full_name='HardwareMessage.gpio_mask', index=1,
|
||||
number=2, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='gpio_value', full_name='HardwareMessage.gpio_value', index=2,
|
||||
number=3, type=4, cpp_type=4, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
_HARDWAREMESSAGE_TYPE,
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=26,
|
||||
serialized_end=228,
|
||||
)
|
||||
|
||||
_HARDWAREMESSAGE.fields_by_name['typ'].enum_type = _HARDWAREMESSAGE_TYPE
|
||||
_HARDWAREMESSAGE_TYPE.containing_type = _HARDWAREMESSAGE
|
||||
DESCRIPTOR.message_types_by_name['HardwareMessage'] = _HARDWAREMESSAGE
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
|
||||
HardwareMessage = _reflection.GeneratedProtocolMessageType('HardwareMessage', (_message.Message,), {
|
||||
'DESCRIPTOR' : _HARDWAREMESSAGE,
|
||||
'__module__' : 'remote_hardware_pb2'
|
||||
# @@protoc_insertion_point(class_scope:HardwareMessage)
|
||||
})
|
||||
_sym_db.RegisterMessage(HardwareMessage)
|
||||
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
# @@protoc_insertion_point(module_scope)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage"><code class="flex name class">
|
||||
<span>class <span class="ident">HardwareMessage</span></span>
|
||||
<span>(</span><span>**kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Abstract base class for protocol messages.</p>
|
||||
<p>Protocol message classes are almost always generated by the protocol
|
||||
compiler.
|
||||
These generated types subclass Message and implement the methods
|
||||
shown below.</p></div>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>google.protobuf.message.Message</li>
|
||||
</ul>
|
||||
<h3>Class variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.DESCRIPTOR"><code class="name">var <span class="ident">DESCRIPTOR</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.GPIOS_CHANGED"><code class="name">var <span class="ident">GPIOS_CHANGED</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.GPIO_MASK_FIELD_NUMBER"><code class="name">var <span class="ident">GPIO_MASK_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.GPIO_VALUE_FIELD_NUMBER"><code class="name">var <span class="ident">GPIO_VALUE_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.READ_GPIOS"><code class="name">var <span class="ident">READ_GPIOS</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.READ_GPIOS_REPLY"><code class="name">var <span class="ident">READ_GPIOS_REPLY</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.TYP_FIELD_NUMBER"><code class="name">var <span class="ident">TYP_FIELD_NUMBER</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.Type"><code class="name">var <span class="ident">Type</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.UNSET"><code class="name">var <span class="ident">UNSET</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.WATCH_GPIOS"><code class="name">var <span class="ident">WATCH_GPIOS</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.WRITE_GPIOS"><code class="name">var <span class="ident">WRITE_GPIOS</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Static methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.FromString"><code class="name flex">
|
||||
<span>def <span class="ident">FromString</span></span>(<span>s)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def FromString(s):
|
||||
message = cls()
|
||||
message.MergeFromString(s)
|
||||
return message</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.RegisterExtension"><code class="name flex">
|
||||
<span>def <span class="ident">RegisterExtension</span></span>(<span>extension_handle)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def RegisterExtension(extension_handle):
|
||||
extension_handle.containing_type = cls.DESCRIPTOR
|
||||
# TODO(amauryfa): Use cls.MESSAGE_FACTORY.pool when available.
|
||||
# pylint: disable=protected-access
|
||||
cls.DESCRIPTOR.file.pool._AddExtensionDescriptor(extension_handle)
|
||||
_AttachFieldHelpers(cls, extension_handle)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Instance variables</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.gpio_mask"><code class="name">var <span class="ident">gpio_mask</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for gpio_mask.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
# TODO(protobuf-team): This may be broken since there may not be
|
||||
# default_value. Combine with has_default_value somehow.
|
||||
return self._fields.get(field, default_value)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.gpio_value"><code class="name">var <span class="ident">gpio_value</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for gpio_value.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
# TODO(protobuf-team): This may be broken since there may not be
|
||||
# default_value. Combine with has_default_value somehow.
|
||||
return self._fields.get(field, default_value)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.typ"><code class="name">var <span class="ident">typ</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Getter for typ.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def getter(self):
|
||||
# TODO(protobuf-team): This may be broken since there may not be
|
||||
# default_value. Combine with has_default_value somehow.
|
||||
return self._fields.get(field, default_value)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.ByteSize"><code class="name flex">
|
||||
<span>def <span class="ident">ByteSize</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ByteSize(self):
|
||||
if not self._cached_byte_size_dirty:
|
||||
return self._cached_byte_size
|
||||
|
||||
size = 0
|
||||
descriptor = self.DESCRIPTOR
|
||||
if descriptor.GetOptions().map_entry:
|
||||
# Fields of map entry should always be serialized.
|
||||
size = descriptor.fields_by_name['key']._sizer(self.key)
|
||||
size += descriptor.fields_by_name['value']._sizer(self.value)
|
||||
else:
|
||||
for field_descriptor, field_value in self.ListFields():
|
||||
size += field_descriptor._sizer(field_value)
|
||||
for tag_bytes, value_bytes in self._unknown_fields:
|
||||
size += len(tag_bytes) + len(value_bytes)
|
||||
|
||||
self._cached_byte_size = size
|
||||
self._cached_byte_size_dirty = False
|
||||
self._listener_for_children.dirty = False
|
||||
return size</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.Clear"><code class="name flex">
|
||||
<span>def <span class="ident">Clear</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _Clear(self):
|
||||
# Clear fields.
|
||||
self._fields = {}
|
||||
self._unknown_fields = ()
|
||||
# pylint: disable=protected-access
|
||||
if self._unknown_field_set is not None:
|
||||
self._unknown_field_set._clear()
|
||||
self._unknown_field_set = None
|
||||
|
||||
self._oneofs = {}
|
||||
self._Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.ClearField"><code class="name flex">
|
||||
<span>def <span class="ident">ClearField</span></span>(<span>self, field_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ClearField(self, field_name):
|
||||
try:
|
||||
field = message_descriptor.fields_by_name[field_name]
|
||||
except KeyError:
|
||||
try:
|
||||
field = message_descriptor.oneofs_by_name[field_name]
|
||||
if field in self._oneofs:
|
||||
field = self._oneofs[field]
|
||||
else:
|
||||
return
|
||||
except KeyError:
|
||||
raise ValueError('Protocol message %s has no "%s" field.' %
|
||||
(message_descriptor.name, field_name))
|
||||
|
||||
if field in self._fields:
|
||||
# To match the C++ implementation, we need to invalidate iterators
|
||||
# for map fields when ClearField() happens.
|
||||
if hasattr(self._fields[field], 'InvalidateIterators'):
|
||||
self._fields[field].InvalidateIterators()
|
||||
|
||||
# Note: If the field is a sub-message, its listener will still point
|
||||
# at us. That's fine, because the worst than can happen is that it
|
||||
# will call _Modified() and invalidate our byte size. Big deal.
|
||||
del self._fields[field]
|
||||
|
||||
if self._oneofs.get(field.containing_oneof, None) is field:
|
||||
del self._oneofs[field.containing_oneof]
|
||||
|
||||
# Always call _Modified() -- even if nothing was changed, this is
|
||||
# a mutating method, and thus calling it should cause the field to become
|
||||
# present in the parent message.
|
||||
self._Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.DiscardUnknownFields"><code class="name flex">
|
||||
<span>def <span class="ident">DiscardUnknownFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _DiscardUnknownFields(self):
|
||||
self._unknown_fields = []
|
||||
self._unknown_field_set = None # pylint: disable=protected-access
|
||||
for field, value in self.ListFields():
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if _IsMapField(field):
|
||||
if _IsMessageMapField(field):
|
||||
for key in value:
|
||||
value[key].DiscardUnknownFields()
|
||||
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
for sub_message in value:
|
||||
sub_message.DiscardUnknownFields()
|
||||
else:
|
||||
value.DiscardUnknownFields()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.FindInitializationErrors"><code class="name flex">
|
||||
<span>def <span class="ident">FindInitializationErrors</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Finds required fields which are not initialized.</p>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>A list of strings.
|
||||
Each string is a path to an uninitialized field from
|
||||
the top-level message, e.g. "foo.bar[5].baz".</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def FindInitializationErrors(self):
|
||||
"""Finds required fields which are not initialized.
|
||||
|
||||
Returns:
|
||||
A list of strings. Each string is a path to an uninitialized field from
|
||||
the top-level message, e.g. "foo.bar[5].baz".
|
||||
"""
|
||||
|
||||
errors = [] # simplify things
|
||||
|
||||
for field in required_fields:
|
||||
if not self.HasField(field.name):
|
||||
errors.append(field.name)
|
||||
|
||||
for field, value in self.ListFields():
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if field.is_extension:
|
||||
name = '(%s)' % field.full_name
|
||||
else:
|
||||
name = field.name
|
||||
|
||||
if _IsMapField(field):
|
||||
if _IsMessageMapField(field):
|
||||
for key in value:
|
||||
element = value[key]
|
||||
prefix = '%s[%s].' % (name, key)
|
||||
sub_errors = element.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
else:
|
||||
# ScalarMaps can't have any initialization errors.
|
||||
pass
|
||||
elif field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
for i in range(len(value)):
|
||||
element = value[i]
|
||||
prefix = '%s[%d].' % (name, i)
|
||||
sub_errors = element.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
else:
|
||||
prefix = name + '.'
|
||||
sub_errors = value.FindInitializationErrors()
|
||||
errors += [prefix + error for error in sub_errors]
|
||||
|
||||
return errors</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.HasField"><code class="name flex">
|
||||
<span>def <span class="ident">HasField</span></span>(<span>self, field_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def HasField(self, field_name):
|
||||
try:
|
||||
field = hassable_fields[field_name]
|
||||
except KeyError:
|
||||
raise ValueError(error_msg % (message_descriptor.full_name, field_name))
|
||||
|
||||
if isinstance(field, descriptor_mod.OneofDescriptor):
|
||||
try:
|
||||
return HasField(self, self._oneofs[field].name)
|
||||
except KeyError:
|
||||
return False
|
||||
else:
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
value = self._fields.get(field)
|
||||
return value is not None and value._is_present_in_parent
|
||||
else:
|
||||
return field in self._fields</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.IsInitialized"><code class="name flex">
|
||||
<span>def <span class="ident">IsInitialized</span></span>(<span>self, errors=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Checks if all required fields of a message are set.</p>
|
||||
<h2 id="args">Args</h2>
|
||||
<dl>
|
||||
<dt><strong><code>errors</code></strong></dt>
|
||||
<dd>A list which, if provided, will be populated with the field
|
||||
paths of all missing required fields.</dd>
|
||||
</dl>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>True iff the specified message has all required fields set.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def IsInitialized(self, errors=None):
|
||||
"""Checks if all required fields of a message are set.
|
||||
|
||||
Args:
|
||||
errors: A list which, if provided, will be populated with the field
|
||||
paths of all missing required fields.
|
||||
|
||||
Returns:
|
||||
True iff the specified message has all required fields set.
|
||||
"""
|
||||
|
||||
# Performance is critical so we avoid HasField() and ListFields().
|
||||
|
||||
for field in required_fields:
|
||||
if (field not in self._fields or
|
||||
(field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
|
||||
not self._fields[field]._is_present_in_parent)):
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
|
||||
for field, value in list(self._fields.items()): # dict can change size!
|
||||
if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
|
||||
if field.label == _FieldDescriptor.LABEL_REPEATED:
|
||||
if (field.message_type.has_options and
|
||||
field.message_type.GetOptions().map_entry):
|
||||
continue
|
||||
for element in value:
|
||||
if not element.IsInitialized():
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
elif value._is_present_in_parent and not value.IsInitialized():
|
||||
if errors is not None:
|
||||
errors.extend(self.FindInitializationErrors())
|
||||
return False
|
||||
|
||||
return True</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.ListFields"><code class="name flex">
|
||||
<span>def <span class="ident">ListFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ListFields(self):
|
||||
all_fields = [item for item in self._fields.items() if _IsPresent(item)]
|
||||
all_fields.sort(key = lambda item: item[0].number)
|
||||
return all_fields</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.MergeFrom"><code class="name flex">
|
||||
<span>def <span class="ident">MergeFrom</span></span>(<span>self, msg)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def MergeFrom(self, msg):
|
||||
if not isinstance(msg, cls):
|
||||
raise TypeError(
|
||||
'Parameter to MergeFrom() must be instance of same class: '
|
||||
'expected %s got %s.' % (_FullyQualifiedClassName(cls),
|
||||
_FullyQualifiedClassName(msg.__class__)))
|
||||
|
||||
assert msg is not self
|
||||
self._Modified()
|
||||
|
||||
fields = self._fields
|
||||
|
||||
for field, value in msg._fields.items():
|
||||
if field.label == LABEL_REPEATED:
|
||||
field_value = fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
fields[field] = field_value
|
||||
field_value.MergeFrom(value)
|
||||
elif field.cpp_type == CPPTYPE_MESSAGE:
|
||||
if value._is_present_in_parent:
|
||||
field_value = fields.get(field)
|
||||
if field_value is None:
|
||||
# Construct a new object to represent this field.
|
||||
field_value = field._default_constructor(self)
|
||||
fields[field] = field_value
|
||||
field_value.MergeFrom(value)
|
||||
else:
|
||||
self._fields[field] = value
|
||||
if field.containing_oneof:
|
||||
self._UpdateOneofState(field)
|
||||
|
||||
if msg._unknown_fields:
|
||||
if not self._unknown_fields:
|
||||
self._unknown_fields = []
|
||||
self._unknown_fields.extend(msg._unknown_fields)
|
||||
# pylint: disable=protected-access
|
||||
if self._unknown_field_set is None:
|
||||
self._unknown_field_set = containers.UnknownFieldSet()
|
||||
self._unknown_field_set._extend(msg._unknown_field_set)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.MergeFromString"><code class="name flex">
|
||||
<span>def <span class="ident">MergeFromString</span></span>(<span>self, serialized)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def MergeFromString(self, serialized):
|
||||
serialized = memoryview(serialized)
|
||||
length = len(serialized)
|
||||
try:
|
||||
if self._InternalParse(serialized, 0, length) != length:
|
||||
# The only reason _InternalParse would return early is if it
|
||||
# encountered an end-group tag.
|
||||
raise message_mod.DecodeError('Unexpected end-group tag.')
|
||||
except (IndexError, TypeError):
|
||||
# Now ord(buf[p:p+1]) == ord('') gets TypeError.
|
||||
raise message_mod.DecodeError('Truncated message.')
|
||||
except struct.error as e:
|
||||
raise message_mod.DecodeError(e)
|
||||
return length # Return this for legacy reasons.</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.SerializePartialToString"><code class="name flex">
|
||||
<span>def <span class="ident">SerializePartialToString</span></span>(<span>self, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def SerializePartialToString(self, **kwargs):
|
||||
out = BytesIO()
|
||||
self._InternalSerialize(out.write, **kwargs)
|
||||
return out.getvalue()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.SerializeToString"><code class="name flex">
|
||||
<span>def <span class="ident">SerializeToString</span></span>(<span>self, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def SerializeToString(self, **kwargs):
|
||||
# Check if the message has all of its required fields set.
|
||||
if not self.IsInitialized():
|
||||
raise message_mod.EncodeError(
|
||||
'Message %s is missing required fields: %s' % (
|
||||
self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
|
||||
return self.SerializePartialToString(**kwargs)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.SetInParent"><code class="name flex">
|
||||
<span>def <span class="ident">SetInParent</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Sets the _cached_byte_size_dirty bit to true,
|
||||
and propagates this to our listener iff this was a state change.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def Modified(self):
|
||||
"""Sets the _cached_byte_size_dirty bit to true,
|
||||
and propagates this to our listener iff this was a state change.
|
||||
"""
|
||||
|
||||
# Note: Some callers check _cached_byte_size_dirty before calling
|
||||
# _Modified() as an extra optimization. So, if this method is ever
|
||||
# changed such that it does stuff even when _cached_byte_size_dirty is
|
||||
# already true, the callers need to be updated.
|
||||
if not self._cached_byte_size_dirty:
|
||||
self._cached_byte_size_dirty = True
|
||||
self._listener_for_children.dirty = True
|
||||
self._is_present_in_parent = True
|
||||
self._listener.Modified()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.UnknownFields"><code class="name flex">
|
||||
<span>def <span class="ident">UnknownFields</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def _UnknownFields(self):
|
||||
if self._unknown_field_set is None: # pylint: disable=protected-access
|
||||
# pylint: disable=protected-access
|
||||
self._unknown_field_set = containers.UnknownFieldSet()
|
||||
return self._unknown_field_set # pylint: disable=protected-access</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.remote_hardware_pb2.HardwareMessage.WhichOneof"><code class="name flex">
|
||||
<span>def <span class="ident">WhichOneof</span></span>(<span>self, oneof_name)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Returns the name of the currently set field inside a oneof, or None.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def WhichOneof(self, oneof_name):
|
||||
"""Returns the name of the currently set field inside a oneof, or None."""
|
||||
try:
|
||||
field = message_descriptor.oneofs_by_name[oneof_name]
|
||||
except KeyError:
|
||||
raise ValueError(
|
||||
'Protocol message has no oneof "%s" field.' % oneof_name)
|
||||
|
||||
nested_field = self._oneofs.get(field, None)
|
||||
if nested_field is not None and self.HasField(nested_field.name):
|
||||
return nested_field.name
|
||||
else:
|
||||
return None</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage" href="#meshtastic.remote_hardware_pb2.HardwareMessage">HardwareMessage</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.ByteSize" href="#meshtastic.remote_hardware_pb2.HardwareMessage.ByteSize">ByteSize</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.Clear" href="#meshtastic.remote_hardware_pb2.HardwareMessage.Clear">Clear</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.ClearField" href="#meshtastic.remote_hardware_pb2.HardwareMessage.ClearField">ClearField</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.DESCRIPTOR" href="#meshtastic.remote_hardware_pb2.HardwareMessage.DESCRIPTOR">DESCRIPTOR</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.DiscardUnknownFields" href="#meshtastic.remote_hardware_pb2.HardwareMessage.DiscardUnknownFields">DiscardUnknownFields</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.FindInitializationErrors" href="#meshtastic.remote_hardware_pb2.HardwareMessage.FindInitializationErrors">FindInitializationErrors</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.FromString" href="#meshtastic.remote_hardware_pb2.HardwareMessage.FromString">FromString</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.GPIOS_CHANGED" href="#meshtastic.remote_hardware_pb2.HardwareMessage.GPIOS_CHANGED">GPIOS_CHANGED</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.GPIO_MASK_FIELD_NUMBER" href="#meshtastic.remote_hardware_pb2.HardwareMessage.GPIO_MASK_FIELD_NUMBER">GPIO_MASK_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.GPIO_VALUE_FIELD_NUMBER" href="#meshtastic.remote_hardware_pb2.HardwareMessage.GPIO_VALUE_FIELD_NUMBER">GPIO_VALUE_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.HasField" href="#meshtastic.remote_hardware_pb2.HardwareMessage.HasField">HasField</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.IsInitialized" href="#meshtastic.remote_hardware_pb2.HardwareMessage.IsInitialized">IsInitialized</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.ListFields" href="#meshtastic.remote_hardware_pb2.HardwareMessage.ListFields">ListFields</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.MergeFrom" href="#meshtastic.remote_hardware_pb2.HardwareMessage.MergeFrom">MergeFrom</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.MergeFromString" href="#meshtastic.remote_hardware_pb2.HardwareMessage.MergeFromString">MergeFromString</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.READ_GPIOS" href="#meshtastic.remote_hardware_pb2.HardwareMessage.READ_GPIOS">READ_GPIOS</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.READ_GPIOS_REPLY" href="#meshtastic.remote_hardware_pb2.HardwareMessage.READ_GPIOS_REPLY">READ_GPIOS_REPLY</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.RegisterExtension" href="#meshtastic.remote_hardware_pb2.HardwareMessage.RegisterExtension">RegisterExtension</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.SerializePartialToString" href="#meshtastic.remote_hardware_pb2.HardwareMessage.SerializePartialToString">SerializePartialToString</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.SerializeToString" href="#meshtastic.remote_hardware_pb2.HardwareMessage.SerializeToString">SerializeToString</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.SetInParent" href="#meshtastic.remote_hardware_pb2.HardwareMessage.SetInParent">SetInParent</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.TYP_FIELD_NUMBER" href="#meshtastic.remote_hardware_pb2.HardwareMessage.TYP_FIELD_NUMBER">TYP_FIELD_NUMBER</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.Type" href="#meshtastic.remote_hardware_pb2.HardwareMessage.Type">Type</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.UNSET" href="#meshtastic.remote_hardware_pb2.HardwareMessage.UNSET">UNSET</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.UnknownFields" href="#meshtastic.remote_hardware_pb2.HardwareMessage.UnknownFields">UnknownFields</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.WATCH_GPIOS" href="#meshtastic.remote_hardware_pb2.HardwareMessage.WATCH_GPIOS">WATCH_GPIOS</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.WRITE_GPIOS" href="#meshtastic.remote_hardware_pb2.HardwareMessage.WRITE_GPIOS">WRITE_GPIOS</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.WhichOneof" href="#meshtastic.remote_hardware_pb2.HardwareMessage.WhichOneof">WhichOneof</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.gpio_mask" href="#meshtastic.remote_hardware_pb2.HardwareMessage.gpio_mask">gpio_mask</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.gpio_value" href="#meshtastic.remote_hardware_pb2.HardwareMessage.gpio_value">gpio_value</a></code></li>
|
||||
<li><code><a title="meshtastic.remote_hardware_pb2.HardwareMessage.typ" href="#meshtastic.remote_hardware_pb2.HardwareMessage.typ">typ</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
254
docs/meshtastic/serial_interface.html
Normal file
254
docs/meshtastic/serial_interface.html
Normal file
@@ -0,0 +1,254 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.serial_interface API documentation</title>
|
||||
<meta name="description" content="Serial interface class" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.serial_interface</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Serial interface class</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">""" Serial interface class
|
||||
"""
|
||||
import logging
|
||||
import platform
|
||||
import os
|
||||
import stat
|
||||
import serial
|
||||
|
||||
import meshtastic.util
|
||||
from .stream_interface import StreamInterface
|
||||
|
||||
class SerialInterface(StreamInterface):
|
||||
"""Interface class for meshtastic devices over a serial link"""
|
||||
|
||||
def __init__(self, devPath=None, debugOut=None, noProto=False, connectNow=True):
|
||||
"""Constructor, opens a connection to a specified serial port, or if unspecified try to
|
||||
find one Meshtastic device by probing
|
||||
|
||||
Keyword Arguments:
|
||||
devPath {string} -- A filepath to a device, i.e. /dev/ttyUSB0 (default: {None})
|
||||
debugOut {stream} -- If a stream is provided, any debug serial output from the device will be emitted to that stream. (default: {None})
|
||||
"""
|
||||
|
||||
if devPath is None:
|
||||
ports = meshtastic.util.findPorts()
|
||||
logging.debug(f"ports:{ports}")
|
||||
if len(ports) == 0:
|
||||
meshtastic.util.our_exit("Warning: No Meshtastic devices detected.")
|
||||
elif len(ports) > 1:
|
||||
message = "Warning: Multiple serial ports were detected so one serial port must be specified with the '--port'.\n"
|
||||
message += f" Ports detected:{ports}"
|
||||
meshtastic.util.our_exit(message)
|
||||
else:
|
||||
devPath = ports[0]
|
||||
|
||||
logging.debug(f"Connecting to {devPath}")
|
||||
|
||||
# Note: we provide None for port here, because we will be opening it later
|
||||
self.stream = serial.Serial(
|
||||
None, 921600, exclusive=True, timeout=0.5, write_timeout=0)
|
||||
|
||||
# rts=False Needed to prevent TBEAMs resetting on OSX, because rts is connected to reset
|
||||
self.stream.port = devPath
|
||||
|
||||
# HACK: If the platform driving the serial port is unable to leave the RTS pin in high-impedance
|
||||
# mode, set RTS to false so that the device platform won't be reset spuriously.
|
||||
# Linux does this properly, so don't apply this hack on Linux (because it makes the reset button not work).
|
||||
if self._hostPlatformAlwaysDrivesUartRts():
|
||||
self.stream.rts = False
|
||||
self.stream.open()
|
||||
|
||||
StreamInterface.__init__(
|
||||
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow)
|
||||
|
||||
"""true if platform driving the serial port is Windows Subsystem for Linux 1."""
|
||||
def _isWsl1(self):
|
||||
# WSL1 identifies itself as Linux, but has a special char device at /dev/lxss for use with session control,
|
||||
# e.g. /init. We should treat WSL1 as Windows for the RTS-driving hack because the underlying platfrom
|
||||
# serial driver for the CP21xx still exhibits the buggy behavior.
|
||||
# WSL2 is not covered here, as it does not (as of 2021-May-25) support the appropriate functionality to
|
||||
# share or pass-through serial ports.
|
||||
try:
|
||||
# Claims to be Linux, but has /dev/lxss; must be WSL 1
|
||||
return platform.system() == 'Linux' and stat.S_ISCHR(os.stat('/dev/lxss').st_mode)
|
||||
except:
|
||||
# Couldn't stat /dev/lxss special device; not WSL1
|
||||
return False
|
||||
|
||||
def _hostPlatformAlwaysDrivesUartRts(self):
|
||||
# OS-X/Windows seems to have a bug in its CP21xx serial drivers. It ignores that we asked for no RTSCTS
|
||||
# control and will always drive RTS either high or low (rather than letting the CP102 leave
|
||||
# it as an open-collector floating pin).
|
||||
# TODO: When WSL2 supports USB passthrough, this will get messier. If/when WSL2 gets virtual serial
|
||||
# ports that "share" the Windows serial port (and thus the Windows drivers), this code will need to be
|
||||
# updated to reflect that as well -- or if T-Beams get made with an alternate USB to UART bridge that has
|
||||
# a less buggy driver.
|
||||
return platform.system() != 'Linux' or self._isWsl1()</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.serial_interface.SerialInterface"><code class="flex name class">
|
||||
<span>class <span class="ident">SerialInterface</span></span>
|
||||
<span>(</span><span>devPath=None, debugOut=None, noProto=False, connectNow=True)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Interface class for meshtastic devices over a serial link</p>
|
||||
<p>Constructor, opens a connection to a specified serial port, or if unspecified try to
|
||||
find one Meshtastic device by probing</p>
|
||||
<p>Keyword Arguments:
|
||||
devPath {string} – A filepath to a device, i.e. /dev/ttyUSB0 (default: {None})
|
||||
debugOut {stream} – If a stream is provided, any debug serial output from the device will be emitted to that stream. (default: {None})</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class SerialInterface(StreamInterface):
|
||||
"""Interface class for meshtastic devices over a serial link"""
|
||||
|
||||
def __init__(self, devPath=None, debugOut=None, noProto=False, connectNow=True):
|
||||
"""Constructor, opens a connection to a specified serial port, or if unspecified try to
|
||||
find one Meshtastic device by probing
|
||||
|
||||
Keyword Arguments:
|
||||
devPath {string} -- A filepath to a device, i.e. /dev/ttyUSB0 (default: {None})
|
||||
debugOut {stream} -- If a stream is provided, any debug serial output from the device will be emitted to that stream. (default: {None})
|
||||
"""
|
||||
|
||||
if devPath is None:
|
||||
ports = meshtastic.util.findPorts()
|
||||
logging.debug(f"ports:{ports}")
|
||||
if len(ports) == 0:
|
||||
meshtastic.util.our_exit("Warning: No Meshtastic devices detected.")
|
||||
elif len(ports) > 1:
|
||||
message = "Warning: Multiple serial ports were detected so one serial port must be specified with the '--port'.\n"
|
||||
message += f" Ports detected:{ports}"
|
||||
meshtastic.util.our_exit(message)
|
||||
else:
|
||||
devPath = ports[0]
|
||||
|
||||
logging.debug(f"Connecting to {devPath}")
|
||||
|
||||
# Note: we provide None for port here, because we will be opening it later
|
||||
self.stream = serial.Serial(
|
||||
None, 921600, exclusive=True, timeout=0.5, write_timeout=0)
|
||||
|
||||
# rts=False Needed to prevent TBEAMs resetting on OSX, because rts is connected to reset
|
||||
self.stream.port = devPath
|
||||
|
||||
# HACK: If the platform driving the serial port is unable to leave the RTS pin in high-impedance
|
||||
# mode, set RTS to false so that the device platform won't be reset spuriously.
|
||||
# Linux does this properly, so don't apply this hack on Linux (because it makes the reset button not work).
|
||||
if self._hostPlatformAlwaysDrivesUartRts():
|
||||
self.stream.rts = False
|
||||
self.stream.open()
|
||||
|
||||
StreamInterface.__init__(
|
||||
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow)
|
||||
|
||||
"""true if platform driving the serial port is Windows Subsystem for Linux 1."""
|
||||
def _isWsl1(self):
|
||||
# WSL1 identifies itself as Linux, but has a special char device at /dev/lxss for use with session control,
|
||||
# e.g. /init. We should treat WSL1 as Windows for the RTS-driving hack because the underlying platfrom
|
||||
# serial driver for the CP21xx still exhibits the buggy behavior.
|
||||
# WSL2 is not covered here, as it does not (as of 2021-May-25) support the appropriate functionality to
|
||||
# share or pass-through serial ports.
|
||||
try:
|
||||
# Claims to be Linux, but has /dev/lxss; must be WSL 1
|
||||
return platform.system() == 'Linux' and stat.S_ISCHR(os.stat('/dev/lxss').st_mode)
|
||||
except:
|
||||
# Couldn't stat /dev/lxss special device; not WSL1
|
||||
return False
|
||||
|
||||
def _hostPlatformAlwaysDrivesUartRts(self):
|
||||
# OS-X/Windows seems to have a bug in its CP21xx serial drivers. It ignores that we asked for no RTSCTS
|
||||
# control and will always drive RTS either high or low (rather than letting the CP102 leave
|
||||
# it as an open-collector floating pin).
|
||||
# TODO: When WSL2 supports USB passthrough, this will get messier. If/when WSL2 gets virtual serial
|
||||
# ports that "share" the Windows serial port (and thus the Windows drivers), this code will need to be
|
||||
# updated to reflect that as well -- or if T-Beams get made with an alternate USB to UART bridge that has
|
||||
# a less buggy driver.
|
||||
return platform.system() != 'Linux' or self._isWsl1()</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="meshtastic.stream_interface.StreamInterface" href="stream_interface.html#meshtastic.stream_interface.StreamInterface">StreamInterface</a></li>
|
||||
<li><a title="meshtastic.mesh_interface.MeshInterface" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface">MeshInterface</a></li>
|
||||
</ul>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="meshtastic.stream_interface.StreamInterface" href="stream_interface.html#meshtastic.stream_interface.StreamInterface">StreamInterface</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.close" href="stream_interface.html#meshtastic.stream_interface.StreamInterface.close">close</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.connect" href="stream_interface.html#meshtastic.stream_interface.StreamInterface.connect">connect</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getLongName" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getLongName">getLongName</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getMyNodeInfo" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getMyNodeInfo">getMyNodeInfo</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getMyUser" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getMyUser">getMyUser</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getNode" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getNode">getNode</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getShortName" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getShortName">getShortName</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.sendData" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendData">sendData</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.sendPosition" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendPosition">sendPosition</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.sendText" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendText">sendText</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.showInfo" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.showInfo">showInfo</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.showNodes" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.showNodes">showNodes</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.waitForConfig" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.waitForConfig">waitForConfig</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.serial_interface.SerialInterface" href="#meshtastic.serial_interface.SerialInterface">SerialInterface</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
1165
docs/meshtastic/storeforward_pb2.html
Normal file
1165
docs/meshtastic/storeforward_pb2.html
Normal file
File diff suppressed because it is too large
Load Diff
519
docs/meshtastic/stream_interface.html
Normal file
519
docs/meshtastic/stream_interface.html
Normal file
@@ -0,0 +1,519 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.stream_interface API documentation</title>
|
||||
<meta name="description" content="Stream Interface base class" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.stream_interface</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Stream Interface base class</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Stream Interface base class
|
||||
"""
|
||||
import logging
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
import serial
|
||||
|
||||
|
||||
from .mesh_interface import MeshInterface
|
||||
from .util import stripnl
|
||||
|
||||
|
||||
START1 = 0x94
|
||||
START2 = 0xc3
|
||||
HEADER_LEN = 4
|
||||
MAX_TO_FROM_RADIO_SIZE = 512
|
||||
|
||||
|
||||
class StreamInterface(MeshInterface):
|
||||
"""Interface class for meshtastic devices over a stream link (serial, TCP, etc)"""
|
||||
|
||||
def __init__(self, debugOut=None, noProto=False, connectNow=True):
|
||||
"""Constructor, opens a connection to self.stream
|
||||
|
||||
Keyword Arguments:
|
||||
debugOut {stream} -- If a stream is provided, any debug serial output from the
|
||||
device will be emitted to that stream. (default: {None})
|
||||
|
||||
Raises:
|
||||
Exception: [description]
|
||||
Exception: [description]
|
||||
"""
|
||||
|
||||
if not hasattr(self, 'stream') and not noProto:
|
||||
raise Exception(
|
||||
"StreamInterface is now abstract (to update existing code create SerialInterface instead)")
|
||||
self._rxBuf = bytes() # empty
|
||||
self._wantExit = False
|
||||
|
||||
# FIXME, figure out why daemon=True causes reader thread to exit too early
|
||||
self._rxThread = threading.Thread(target=self.__reader, args=(), daemon=True)
|
||||
|
||||
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
|
||||
|
||||
# Start the reader thread after superclass constructor completes init
|
||||
if connectNow:
|
||||
self.connect()
|
||||
if not noProto:
|
||||
self.waitForConfig()
|
||||
|
||||
def connect(self):
|
||||
"""Connect to our radio
|
||||
|
||||
Normally this is called automatically by the constructor, but if you
|
||||
passed in connectNow=False you can manually start the reading thread later.
|
||||
"""
|
||||
|
||||
# Send some bogus UART characters to force a sleeping device to wake, and
|
||||
# if the reading statemachine was parsing a bad packet make sure
|
||||
# we write enought start bytes to force it to resync (we don't use START1
|
||||
# because we want to ensure it is looking for START1)
|
||||
p = bytearray([START2] * 32)
|
||||
self._writeBytes(p)
|
||||
time.sleep(0.1) # wait 100ms to give device time to start running
|
||||
|
||||
self._rxThread.start()
|
||||
|
||||
self._startConfig()
|
||||
|
||||
if not self.noProto: # Wait for the db download if using the protocol
|
||||
self._waitConnected()
|
||||
|
||||
def _disconnected(self):
|
||||
"""We override the superclass implementation to close our port"""
|
||||
MeshInterface._disconnected(self)
|
||||
|
||||
logging.debug("Closing our port")
|
||||
# pylint: disable=E0203
|
||||
if not self.stream is None:
|
||||
# pylint: disable=E0203
|
||||
self.stream.close()
|
||||
# pylint: disable=W0201
|
||||
self.stream = None
|
||||
|
||||
def _writeBytes(self, b):
|
||||
"""Write an array of bytes to our stream and flush"""
|
||||
if self.stream: # ignore writes when stream is closed
|
||||
self.stream.write(b)
|
||||
self.stream.flush()
|
||||
|
||||
def _readBytes(self, length):
|
||||
"""Read an array of bytes from our stream"""
|
||||
if self.stream:
|
||||
return self.stream.read(length)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _sendToRadioImpl(self, toRadio):
|
||||
"""Send a ToRadio protobuf to the device"""
|
||||
logging.debug(f"Sending: {stripnl(toRadio)}")
|
||||
b = toRadio.SerializeToString()
|
||||
bufLen = len(b)
|
||||
# We convert into a string, because the TCP code doesn't work with byte arrays
|
||||
header = bytes([START1, START2, (bufLen >> 8) & 0xff, bufLen & 0xff])
|
||||
logging.debug(f'sending header:{header} b:{b}')
|
||||
self._writeBytes(header + b)
|
||||
|
||||
def close(self):
|
||||
"""Close a connection to the device"""
|
||||
logging.debug("Closing stream")
|
||||
MeshInterface.close(self)
|
||||
# pyserial cancel_read doesn't seem to work, therefore we ask the
|
||||
# reader thread to close things for us
|
||||
self._wantExit = True
|
||||
if self._rxThread != threading.current_thread():
|
||||
self._rxThread.join() # wait for it to exit
|
||||
|
||||
def __reader(self):
|
||||
"""The reader thread that reads bytes from our stream"""
|
||||
logging.debug('in __reader()')
|
||||
empty = bytes()
|
||||
|
||||
try:
|
||||
while not self._wantExit:
|
||||
logging.debug("reading character")
|
||||
b = self._readBytes(1)
|
||||
logging.debug("In reader loop")
|
||||
#logging.debug(f"read returned {b}")
|
||||
if len(b) > 0:
|
||||
c = b[0]
|
||||
#logging.debug(f'c:{c}')
|
||||
ptr = len(self._rxBuf)
|
||||
|
||||
# Assume we want to append this byte, fixme use bytearray instead
|
||||
self._rxBuf = self._rxBuf + b
|
||||
|
||||
if ptr == 0: # looking for START1
|
||||
if c != START1:
|
||||
self._rxBuf = empty # failed to find start
|
||||
if self.debugOut is not None:
|
||||
try:
|
||||
self.debugOut.write(b.decode("utf-8"))
|
||||
except:
|
||||
self.debugOut.write('?')
|
||||
|
||||
elif ptr == 1: # looking for START2
|
||||
if c != START2:
|
||||
self._rxBuf = empty # failed to find start2
|
||||
elif ptr >= HEADER_LEN - 1: # we've at least got a header
|
||||
#logging.debug('at least we received a header')
|
||||
# big endian length follows header
|
||||
packetlen = (self._rxBuf[2] << 8) + self._rxBuf[3]
|
||||
|
||||
if ptr == HEADER_LEN - 1: # we _just_ finished reading the header, validate length
|
||||
if packetlen > MAX_TO_FROM_RADIO_SIZE:
|
||||
self._rxBuf = empty # length was out out bounds, restart
|
||||
|
||||
if len(self._rxBuf) != 0 and ptr + 1 >= packetlen + HEADER_LEN:
|
||||
try:
|
||||
self._handleFromRadio(self._rxBuf[HEADER_LEN:])
|
||||
except Exception as ex:
|
||||
logging.error(f"Error while handling message from radio {ex}")
|
||||
traceback.print_exc()
|
||||
self._rxBuf = empty
|
||||
else:
|
||||
# logging.debug(f"timeout")
|
||||
pass
|
||||
except serial.SerialException as ex:
|
||||
if not self._wantExit: # We might intentionally get an exception during shutdown
|
||||
logging.warning(f"Meshtastic serial port disconnected, disconnecting... {ex}")
|
||||
except OSError as ex:
|
||||
if not self._wantExit: # We might intentionally get an exception during shutdown
|
||||
logging.error(f"Unexpected OSError, terminating meshtastic reader... {ex}")
|
||||
except Exception as ex:
|
||||
logging.error(f"Unexpected exception, terminating meshtastic reader... {ex}")
|
||||
finally:
|
||||
logging.debug("reader is exiting")
|
||||
self._disconnected()</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.stream_interface.StreamInterface"><code class="flex name class">
|
||||
<span>class <span class="ident">StreamInterface</span></span>
|
||||
<span>(</span><span>debugOut=None, noProto=False, connectNow=True)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Interface class for meshtastic devices over a stream link (serial, TCP, etc)</p>
|
||||
<p>Constructor, opens a connection to self.stream</p>
|
||||
<p>Keyword Arguments:
|
||||
debugOut {stream} – If a stream is provided, any debug serial output from the
|
||||
device will be emitted to that stream. (default: {None})</p>
|
||||
<h2 id="raises">Raises</h2>
|
||||
<dl>
|
||||
<dt><code>Exception</code></dt>
|
||||
<dd>[description]</dd>
|
||||
<dt><code>Exception</code></dt>
|
||||
<dd>[description]</dd>
|
||||
</dl></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class StreamInterface(MeshInterface):
|
||||
"""Interface class for meshtastic devices over a stream link (serial, TCP, etc)"""
|
||||
|
||||
def __init__(self, debugOut=None, noProto=False, connectNow=True):
|
||||
"""Constructor, opens a connection to self.stream
|
||||
|
||||
Keyword Arguments:
|
||||
debugOut {stream} -- If a stream is provided, any debug serial output from the
|
||||
device will be emitted to that stream. (default: {None})
|
||||
|
||||
Raises:
|
||||
Exception: [description]
|
||||
Exception: [description]
|
||||
"""
|
||||
|
||||
if not hasattr(self, 'stream') and not noProto:
|
||||
raise Exception(
|
||||
"StreamInterface is now abstract (to update existing code create SerialInterface instead)")
|
||||
self._rxBuf = bytes() # empty
|
||||
self._wantExit = False
|
||||
|
||||
# FIXME, figure out why daemon=True causes reader thread to exit too early
|
||||
self._rxThread = threading.Thread(target=self.__reader, args=(), daemon=True)
|
||||
|
||||
MeshInterface.__init__(self, debugOut=debugOut, noProto=noProto)
|
||||
|
||||
# Start the reader thread after superclass constructor completes init
|
||||
if connectNow:
|
||||
self.connect()
|
||||
if not noProto:
|
||||
self.waitForConfig()
|
||||
|
||||
def connect(self):
|
||||
"""Connect to our radio
|
||||
|
||||
Normally this is called automatically by the constructor, but if you
|
||||
passed in connectNow=False you can manually start the reading thread later.
|
||||
"""
|
||||
|
||||
# Send some bogus UART characters to force a sleeping device to wake, and
|
||||
# if the reading statemachine was parsing a bad packet make sure
|
||||
# we write enought start bytes to force it to resync (we don't use START1
|
||||
# because we want to ensure it is looking for START1)
|
||||
p = bytearray([START2] * 32)
|
||||
self._writeBytes(p)
|
||||
time.sleep(0.1) # wait 100ms to give device time to start running
|
||||
|
||||
self._rxThread.start()
|
||||
|
||||
self._startConfig()
|
||||
|
||||
if not self.noProto: # Wait for the db download if using the protocol
|
||||
self._waitConnected()
|
||||
|
||||
def _disconnected(self):
|
||||
"""We override the superclass implementation to close our port"""
|
||||
MeshInterface._disconnected(self)
|
||||
|
||||
logging.debug("Closing our port")
|
||||
# pylint: disable=E0203
|
||||
if not self.stream is None:
|
||||
# pylint: disable=E0203
|
||||
self.stream.close()
|
||||
# pylint: disable=W0201
|
||||
self.stream = None
|
||||
|
||||
def _writeBytes(self, b):
|
||||
"""Write an array of bytes to our stream and flush"""
|
||||
if self.stream: # ignore writes when stream is closed
|
||||
self.stream.write(b)
|
||||
self.stream.flush()
|
||||
|
||||
def _readBytes(self, length):
|
||||
"""Read an array of bytes from our stream"""
|
||||
if self.stream:
|
||||
return self.stream.read(length)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _sendToRadioImpl(self, toRadio):
|
||||
"""Send a ToRadio protobuf to the device"""
|
||||
logging.debug(f"Sending: {stripnl(toRadio)}")
|
||||
b = toRadio.SerializeToString()
|
||||
bufLen = len(b)
|
||||
# We convert into a string, because the TCP code doesn't work with byte arrays
|
||||
header = bytes([START1, START2, (bufLen >> 8) & 0xff, bufLen & 0xff])
|
||||
logging.debug(f'sending header:{header} b:{b}')
|
||||
self._writeBytes(header + b)
|
||||
|
||||
def close(self):
|
||||
"""Close a connection to the device"""
|
||||
logging.debug("Closing stream")
|
||||
MeshInterface.close(self)
|
||||
# pyserial cancel_read doesn't seem to work, therefore we ask the
|
||||
# reader thread to close things for us
|
||||
self._wantExit = True
|
||||
if self._rxThread != threading.current_thread():
|
||||
self._rxThread.join() # wait for it to exit
|
||||
|
||||
def __reader(self):
|
||||
"""The reader thread that reads bytes from our stream"""
|
||||
logging.debug('in __reader()')
|
||||
empty = bytes()
|
||||
|
||||
try:
|
||||
while not self._wantExit:
|
||||
logging.debug("reading character")
|
||||
b = self._readBytes(1)
|
||||
logging.debug("In reader loop")
|
||||
#logging.debug(f"read returned {b}")
|
||||
if len(b) > 0:
|
||||
c = b[0]
|
||||
#logging.debug(f'c:{c}')
|
||||
ptr = len(self._rxBuf)
|
||||
|
||||
# Assume we want to append this byte, fixme use bytearray instead
|
||||
self._rxBuf = self._rxBuf + b
|
||||
|
||||
if ptr == 0: # looking for START1
|
||||
if c != START1:
|
||||
self._rxBuf = empty # failed to find start
|
||||
if self.debugOut is not None:
|
||||
try:
|
||||
self.debugOut.write(b.decode("utf-8"))
|
||||
except:
|
||||
self.debugOut.write('?')
|
||||
|
||||
elif ptr == 1: # looking for START2
|
||||
if c != START2:
|
||||
self._rxBuf = empty # failed to find start2
|
||||
elif ptr >= HEADER_LEN - 1: # we've at least got a header
|
||||
#logging.debug('at least we received a header')
|
||||
# big endian length follows header
|
||||
packetlen = (self._rxBuf[2] << 8) + self._rxBuf[3]
|
||||
|
||||
if ptr == HEADER_LEN - 1: # we _just_ finished reading the header, validate length
|
||||
if packetlen > MAX_TO_FROM_RADIO_SIZE:
|
||||
self._rxBuf = empty # length was out out bounds, restart
|
||||
|
||||
if len(self._rxBuf) != 0 and ptr + 1 >= packetlen + HEADER_LEN:
|
||||
try:
|
||||
self._handleFromRadio(self._rxBuf[HEADER_LEN:])
|
||||
except Exception as ex:
|
||||
logging.error(f"Error while handling message from radio {ex}")
|
||||
traceback.print_exc()
|
||||
self._rxBuf = empty
|
||||
else:
|
||||
# logging.debug(f"timeout")
|
||||
pass
|
||||
except serial.SerialException as ex:
|
||||
if not self._wantExit: # We might intentionally get an exception during shutdown
|
||||
logging.warning(f"Meshtastic serial port disconnected, disconnecting... {ex}")
|
||||
except OSError as ex:
|
||||
if not self._wantExit: # We might intentionally get an exception during shutdown
|
||||
logging.error(f"Unexpected OSError, terminating meshtastic reader... {ex}")
|
||||
except Exception as ex:
|
||||
logging.error(f"Unexpected exception, terminating meshtastic reader... {ex}")
|
||||
finally:
|
||||
logging.debug("reader is exiting")
|
||||
self._disconnected()</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="meshtastic.mesh_interface.MeshInterface" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface">MeshInterface</a></li>
|
||||
</ul>
|
||||
<h3>Subclasses</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="meshtastic.serial_interface.SerialInterface" href="serial_interface.html#meshtastic.serial_interface.SerialInterface">SerialInterface</a></li>
|
||||
<li><a title="meshtastic.tcp_interface.TCPInterface" href="tcp_interface.html#meshtastic.tcp_interface.TCPInterface">TCPInterface</a></li>
|
||||
</ul>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.stream_interface.StreamInterface.close"><code class="name flex">
|
||||
<span>def <span class="ident">close</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Close a connection to the device</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def close(self):
|
||||
"""Close a connection to the device"""
|
||||
logging.debug("Closing stream")
|
||||
MeshInterface.close(self)
|
||||
# pyserial cancel_read doesn't seem to work, therefore we ask the
|
||||
# reader thread to close things for us
|
||||
self._wantExit = True
|
||||
if self._rxThread != threading.current_thread():
|
||||
self._rxThread.join() # wait for it to exit</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.stream_interface.StreamInterface.connect"><code class="name flex">
|
||||
<span>def <span class="ident">connect</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Connect to our radio</p>
|
||||
<p>Normally this is called automatically by the constructor, but if you
|
||||
passed in connectNow=False you can manually start the reading thread later.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def connect(self):
|
||||
"""Connect to our radio
|
||||
|
||||
Normally this is called automatically by the constructor, but if you
|
||||
passed in connectNow=False you can manually start the reading thread later.
|
||||
"""
|
||||
|
||||
# Send some bogus UART characters to force a sleeping device to wake, and
|
||||
# if the reading statemachine was parsing a bad packet make sure
|
||||
# we write enought start bytes to force it to resync (we don't use START1
|
||||
# because we want to ensure it is looking for START1)
|
||||
p = bytearray([START2] * 32)
|
||||
self._writeBytes(p)
|
||||
time.sleep(0.1) # wait 100ms to give device time to start running
|
||||
|
||||
self._rxThread.start()
|
||||
|
||||
self._startConfig()
|
||||
|
||||
if not self.noProto: # Wait for the db download if using the protocol
|
||||
self._waitConnected()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="meshtastic.mesh_interface.MeshInterface" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface">MeshInterface</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getLongName" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getLongName">getLongName</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getMyNodeInfo" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getMyNodeInfo">getMyNodeInfo</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getMyUser" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getMyUser">getMyUser</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getNode" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getNode">getNode</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.getShortName" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getShortName">getShortName</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.sendData" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendData">sendData</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.sendPosition" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendPosition">sendPosition</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.sendText" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendText">sendText</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.showInfo" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.showInfo">showInfo</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.showNodes" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.showNodes">showNodes</a></code></li>
|
||||
<li><code><a title="meshtastic.mesh_interface.MeshInterface.waitForConfig" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.waitForConfig">waitForConfig</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.stream_interface.StreamInterface" href="#meshtastic.stream_interface.StreamInterface">StreamInterface</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.close" href="#meshtastic.stream_interface.StreamInterface.close">close</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.connect" href="#meshtastic.stream_interface.StreamInterface.connect">connect</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
251
docs/meshtastic/tcp_interface.html
Normal file
251
docs/meshtastic/tcp_interface.html
Normal file
@@ -0,0 +1,251 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tcp_interface API documentation</title>
|
||||
<meta name="description" content="TCPInterface class for interfacing with http endpoint" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tcp_interface</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>TCPInterface class for interfacing with http endpoint</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""TCPInterface class for interfacing with http endpoint
|
||||
"""
|
||||
import logging
|
||||
import socket
|
||||
from typing import AnyStr
|
||||
|
||||
from .stream_interface import StreamInterface
|
||||
|
||||
class TCPInterface(StreamInterface):
|
||||
"""Interface class for meshtastic devices over a TCP link"""
|
||||
|
||||
def __init__(self, hostname: AnyStr, debugOut=None, noProto=False,
|
||||
connectNow=True, portNumber=4403):
|
||||
"""Constructor, opens a connection to a specified IP address/hostname
|
||||
|
||||
Keyword Arguments:
|
||||
hostname {string} -- Hostname/IP address of the device to connect to
|
||||
"""
|
||||
|
||||
# Instead of wrapping as a stream, we use the native socket API
|
||||
# self.stream = sock.makefile('rw')
|
||||
self.stream = None
|
||||
|
||||
self.hostname = hostname
|
||||
self.portNumber = portNumber
|
||||
|
||||
if connectNow:
|
||||
logging.debug(f"Connecting to {hostname}")
|
||||
server_address = (hostname, portNumber)
|
||||
sock = socket.create_connection(server_address)
|
||||
self.socket = sock
|
||||
else:
|
||||
self.socket = None
|
||||
|
||||
StreamInterface.__init__(self, debugOut=debugOut, noProto=noProto,
|
||||
connectNow=connectNow)
|
||||
|
||||
def myConnect(self):
|
||||
"""Connect to socket"""
|
||||
server_address = (self.hostname, self.portNumber)
|
||||
sock = socket.create_connection(server_address)
|
||||
self.socket = sock
|
||||
|
||||
def close(self):
|
||||
"""Close a connection to the device"""
|
||||
logging.debug("Closing TCP stream")
|
||||
StreamInterface.close(self)
|
||||
# Sometimes the socket read might be blocked in the reader thread.
|
||||
# Therefore we force the shutdown by closing the socket here
|
||||
self._wantExit = True
|
||||
if not self.socket is None:
|
||||
try:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
except:
|
||||
pass # Ignore errors in shutdown, because we might have a race with the server
|
||||
self.socket.close()
|
||||
|
||||
def _writeBytes(self, b):
|
||||
"""Write an array of bytes to our stream and flush"""
|
||||
self.socket.send(b)
|
||||
|
||||
def _readBytes(self, length):
|
||||
"""Read an array of bytes from our stream"""
|
||||
return self.socket.recv(length)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tcp_interface.TCPInterface"><code class="flex name class">
|
||||
<span>class <span class="ident">TCPInterface</span></span>
|
||||
<span>(</span><span>hostname: ~AnyStr, debugOut=None, noProto=False, connectNow=True, portNumber=4403)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Interface class for meshtastic devices over a TCP link</p>
|
||||
<p>Constructor, opens a connection to a specified IP address/hostname</p>
|
||||
<p>Keyword Arguments:
|
||||
hostname {string} – Hostname/IP address of the device to connect to</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TCPInterface(StreamInterface):
|
||||
"""Interface class for meshtastic devices over a TCP link"""
|
||||
|
||||
def __init__(self, hostname: AnyStr, debugOut=None, noProto=False,
|
||||
connectNow=True, portNumber=4403):
|
||||
"""Constructor, opens a connection to a specified IP address/hostname
|
||||
|
||||
Keyword Arguments:
|
||||
hostname {string} -- Hostname/IP address of the device to connect to
|
||||
"""
|
||||
|
||||
# Instead of wrapping as a stream, we use the native socket API
|
||||
# self.stream = sock.makefile('rw')
|
||||
self.stream = None
|
||||
|
||||
self.hostname = hostname
|
||||
self.portNumber = portNumber
|
||||
|
||||
if connectNow:
|
||||
logging.debug(f"Connecting to {hostname}")
|
||||
server_address = (hostname, portNumber)
|
||||
sock = socket.create_connection(server_address)
|
||||
self.socket = sock
|
||||
else:
|
||||
self.socket = None
|
||||
|
||||
StreamInterface.__init__(self, debugOut=debugOut, noProto=noProto,
|
||||
connectNow=connectNow)
|
||||
|
||||
def myConnect(self):
|
||||
"""Connect to socket"""
|
||||
server_address = (self.hostname, self.portNumber)
|
||||
sock = socket.create_connection(server_address)
|
||||
self.socket = sock
|
||||
|
||||
def close(self):
|
||||
"""Close a connection to the device"""
|
||||
logging.debug("Closing TCP stream")
|
||||
StreamInterface.close(self)
|
||||
# Sometimes the socket read might be blocked in the reader thread.
|
||||
# Therefore we force the shutdown by closing the socket here
|
||||
self._wantExit = True
|
||||
if not self.socket is None:
|
||||
try:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
except:
|
||||
pass # Ignore errors in shutdown, because we might have a race with the server
|
||||
self.socket.close()
|
||||
|
||||
def _writeBytes(self, b):
|
||||
"""Write an array of bytes to our stream and flush"""
|
||||
self.socket.send(b)
|
||||
|
||||
def _readBytes(self, length):
|
||||
"""Read an array of bytes from our stream"""
|
||||
return self.socket.recv(length)</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li><a title="meshtastic.stream_interface.StreamInterface" href="stream_interface.html#meshtastic.stream_interface.StreamInterface">StreamInterface</a></li>
|
||||
<li><a title="meshtastic.mesh_interface.MeshInterface" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface">MeshInterface</a></li>
|
||||
</ul>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.tcp_interface.TCPInterface.myConnect"><code class="name flex">
|
||||
<span>def <span class="ident">myConnect</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Connect to socket</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def myConnect(self):
|
||||
"""Connect to socket"""
|
||||
server_address = (self.hostname, self.portNumber)
|
||||
sock = socket.create_connection(server_address)
|
||||
self.socket = sock</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3>Inherited members</h3>
|
||||
<ul class="hlist">
|
||||
<li><code><b><a title="meshtastic.stream_interface.StreamInterface" href="stream_interface.html#meshtastic.stream_interface.StreamInterface">StreamInterface</a></b></code>:
|
||||
<ul class="hlist">
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.close" href="stream_interface.html#meshtastic.stream_interface.StreamInterface.close">close</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.connect" href="stream_interface.html#meshtastic.stream_interface.StreamInterface.connect">connect</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getLongName" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getLongName">getLongName</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getMyNodeInfo" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getMyNodeInfo">getMyNodeInfo</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getMyUser" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getMyUser">getMyUser</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getNode" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getNode">getNode</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.getShortName" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.getShortName">getShortName</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.sendData" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendData">sendData</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.sendPosition" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendPosition">sendPosition</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.sendText" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.sendText">sendText</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.showInfo" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.showInfo">showInfo</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.showNodes" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.showNodes">showNodes</a></code></li>
|
||||
<li><code><a title="meshtastic.stream_interface.StreamInterface.waitForConfig" href="mesh_interface.html#meshtastic.mesh_interface.MeshInterface.waitForConfig">waitForConfig</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.tcp_interface.TCPInterface" href="#meshtastic.tcp_interface.TCPInterface">TCPInterface</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tcp_interface.TCPInterface.myConnect" href="#meshtastic.tcp_interface.TCPInterface.myConnect">myConnect</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
544
docs/meshtastic/test.html
Normal file
544
docs/meshtastic/test.html
Normal file
@@ -0,0 +1,544 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.test API documentation</title>
|
||||
<meta name="description" content="With two radios connected serially, send and receive test
|
||||
messages and report back if successful." />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.test</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>With two radios connected serially, send and receive test
|
||||
messages and report back if successful.</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""With two radios connected serially, send and receive test
|
||||
messages and report back if successful.
|
||||
"""
|
||||
import logging
|
||||
import time
|
||||
import sys
|
||||
import traceback
|
||||
from dotmap import DotMap
|
||||
from pubsub import pub
|
||||
import meshtastic.util
|
||||
from .__init__ import BROADCAST_NUM
|
||||
from .serial_interface import SerialInterface
|
||||
from .tcp_interface import TCPInterface
|
||||
|
||||
|
||||
"""The interfaces we are using for our tests"""
|
||||
interfaces = None
|
||||
|
||||
"""A list of all packets we received while the current test was running"""
|
||||
receivedPackets = None
|
||||
|
||||
testsRunning = False
|
||||
|
||||
testNumber = 0
|
||||
|
||||
sendingInterface = None
|
||||
|
||||
|
||||
def onReceive(packet, interface):
|
||||
"""Callback invoked when a packet arrives"""
|
||||
if sendingInterface == interface:
|
||||
pass
|
||||
# print("Ignoring sending interface")
|
||||
else:
|
||||
# print(f"From {interface.stream.port}: {packet}")
|
||||
p = DotMap(packet)
|
||||
|
||||
if p.decoded.portnum == "TEXT_MESSAGE_APP":
|
||||
# We only care a about clear text packets
|
||||
if receivedPackets is not None:
|
||||
receivedPackets.append(p)
|
||||
|
||||
|
||||
def onNode(node):
|
||||
"""Callback invoked when the node DB changes"""
|
||||
print(f"Node changed: {node}")
|
||||
|
||||
|
||||
def subscribe():
|
||||
"""Subscribe to the topics the user probably wants to see, prints output to stdout"""
|
||||
|
||||
pub.subscribe(onNode, "meshtastic.node")
|
||||
|
||||
|
||||
def testSend(fromInterface, toInterface, isBroadcast=False, asBinary=False, wantAck=False):
|
||||
"""
|
||||
Sends one test packet between two nodes and then returns success or failure
|
||||
|
||||
Arguments:
|
||||
fromInterface {[type]} -- [description]
|
||||
toInterface {[type]} -- [description]
|
||||
|
||||
Returns:
|
||||
boolean -- True for success
|
||||
"""
|
||||
global receivedPackets
|
||||
receivedPackets = []
|
||||
fromNode = fromInterface.myInfo.my_node_num
|
||||
|
||||
if isBroadcast:
|
||||
toNode = BROADCAST_NUM
|
||||
else:
|
||||
toNode = toInterface.myInfo.my_node_num
|
||||
|
||||
logging.debug(
|
||||
f"Sending test wantAck={wantAck} packet from {fromNode} to {toNode}")
|
||||
global sendingInterface
|
||||
sendingInterface = fromInterface
|
||||
if not asBinary:
|
||||
fromInterface.sendText(f"Test {testNumber}", toNode, wantAck=wantAck)
|
||||
else:
|
||||
fromInterface.sendData((f"Binary {testNumber}").encode(
|
||||
"utf-8"), toNode, wantAck=wantAck)
|
||||
for _ in range(60): # max of 60 secs before we timeout
|
||||
time.sleep(1)
|
||||
if len(receivedPackets) >= 1:
|
||||
return True
|
||||
return False # Failed to send
|
||||
|
||||
|
||||
def runTests(numTests=50, wantAck=False, maxFailures=0):
|
||||
"""Run the tests."""
|
||||
logging.info(f"Running {numTests} tests with wantAck={wantAck}")
|
||||
numFail = 0
|
||||
numSuccess = 0
|
||||
for _ in range(numTests):
|
||||
global testNumber
|
||||
testNumber = testNumber + 1
|
||||
isBroadcast = True
|
||||
# asBinary=(i % 2 == 0)
|
||||
success = testSend(
|
||||
interfaces[0], interfaces[1], isBroadcast, asBinary=False, wantAck=wantAck)
|
||||
if not success:
|
||||
numFail = numFail + 1
|
||||
logging.error(
|
||||
f"Test {testNumber} failed, expected packet not received ({numFail} failures so far)")
|
||||
else:
|
||||
numSuccess = numSuccess + 1
|
||||
logging.info(
|
||||
f"Test {testNumber} succeeded {numSuccess} successes {numFail} failures so far")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
if numFail > maxFailures:
|
||||
logging.error("Too many failures! Test failed!")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def testThread(numTests=50):
|
||||
"""Test thread"""
|
||||
logging.info("Found devices, starting tests...")
|
||||
result = runTests(numTests, wantAck=True)
|
||||
if result:
|
||||
# Run another test
|
||||
# Allow a few dropped packets
|
||||
result = runTests(numTests, wantAck=False, maxFailures=1)
|
||||
return result
|
||||
|
||||
|
||||
def onConnection(topic=pub.AUTO_TOPIC):
|
||||
"""Callback invoked when we connect/disconnect from a radio"""
|
||||
print(f"Connection changed: {topic.getName()}")
|
||||
|
||||
|
||||
def openDebugLog(portName):
|
||||
"""Open the debug log file"""
|
||||
debugname = "log" + portName.replace("/", "_")
|
||||
logging.info(f"Writing serial debugging to {debugname}")
|
||||
return open(debugname, 'w+', buffering=1, encoding='utf8')
|
||||
|
||||
|
||||
def testAll(numTests=5):
|
||||
"""
|
||||
Run a series of tests using devices we can find.
|
||||
This is called from the cli with the "--test" option.
|
||||
|
||||
"""
|
||||
ports = meshtastic.util.findPorts()
|
||||
if len(ports) < 2:
|
||||
meshtastic.util.our_exit("Warning: Must have at least two devices connected to USB.")
|
||||
|
||||
pub.subscribe(onConnection, "meshtastic.connection")
|
||||
pub.subscribe(onReceive, "meshtastic.receive")
|
||||
global interfaces
|
||||
interfaces = list(map(lambda port: SerialInterface(
|
||||
port, debugOut=openDebugLog(port), connectNow=True), ports))
|
||||
|
||||
logging.info("Ports opened, starting test")
|
||||
result = testThread(numTests)
|
||||
|
||||
for i in interfaces:
|
||||
i.close()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def testSimulator():
|
||||
"""
|
||||
Assume that someone has launched meshtastic-native as a simulated node.
|
||||
Talk to that node over TCP, do some operations and if they are successful
|
||||
exit the process with a success code, else exit with a non zero exit code.
|
||||
|
||||
Run with
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||
"""
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.info("Connecting to simulator on localhost!")
|
||||
try:
|
||||
iface = TCPInterface("localhost")
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
iface.localNode.exitSimulator()
|
||||
iface.close()
|
||||
logging.info("Integration test successful!")
|
||||
except:
|
||||
print("Error while testing simulator:", sys.exc_info()[0])
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
sys.exit(0)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-variables">Global variables</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.test.interfaces"><code class="name">var <span class="ident">interfaces</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A list of all packets we received while the current test was running</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.test.onConnection"><code class="name flex">
|
||||
<span>def <span class="ident">onConnection</span></span>(<span>topic=pubsub.core.callables.AUTO_TOPIC)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Callback invoked when we connect/disconnect from a radio</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def onConnection(topic=pub.AUTO_TOPIC):
|
||||
"""Callback invoked when we connect/disconnect from a radio"""
|
||||
print(f"Connection changed: {topic.getName()}")</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.test.onNode"><code class="name flex">
|
||||
<span>def <span class="ident">onNode</span></span>(<span>node)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Callback invoked when the node DB changes</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def onNode(node):
|
||||
"""Callback invoked when the node DB changes"""
|
||||
print(f"Node changed: {node}")</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.test.onReceive"><code class="name flex">
|
||||
<span>def <span class="ident">onReceive</span></span>(<span>packet, interface)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Callback invoked when a packet arrives</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def onReceive(packet, interface):
|
||||
"""Callback invoked when a packet arrives"""
|
||||
if sendingInterface == interface:
|
||||
pass
|
||||
# print("Ignoring sending interface")
|
||||
else:
|
||||
# print(f"From {interface.stream.port}: {packet}")
|
||||
p = DotMap(packet)
|
||||
|
||||
if p.decoded.portnum == "TEXT_MESSAGE_APP":
|
||||
# We only care a about clear text packets
|
||||
if receivedPackets is not None:
|
||||
receivedPackets.append(p)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.test.openDebugLog"><code class="name flex">
|
||||
<span>def <span class="ident">openDebugLog</span></span>(<span>portName)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Open the debug log file</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def openDebugLog(portName):
|
||||
"""Open the debug log file"""
|
||||
debugname = "log" + portName.replace("/", "_")
|
||||
logging.info(f"Writing serial debugging to {debugname}")
|
||||
return open(debugname, 'w+', buffering=1, encoding='utf8')</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.test.runTests"><code class="name flex">
|
||||
<span>def <span class="ident">runTests</span></span>(<span>numTests=50, wantAck=False, maxFailures=0)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Run the tests.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def runTests(numTests=50, wantAck=False, maxFailures=0):
|
||||
"""Run the tests."""
|
||||
logging.info(f"Running {numTests} tests with wantAck={wantAck}")
|
||||
numFail = 0
|
||||
numSuccess = 0
|
||||
for _ in range(numTests):
|
||||
global testNumber
|
||||
testNumber = testNumber + 1
|
||||
isBroadcast = True
|
||||
# asBinary=(i % 2 == 0)
|
||||
success = testSend(
|
||||
interfaces[0], interfaces[1], isBroadcast, asBinary=False, wantAck=wantAck)
|
||||
if not success:
|
||||
numFail = numFail + 1
|
||||
logging.error(
|
||||
f"Test {testNumber} failed, expected packet not received ({numFail} failures so far)")
|
||||
else:
|
||||
numSuccess = numSuccess + 1
|
||||
logging.info(
|
||||
f"Test {testNumber} succeeded {numSuccess} successes {numFail} failures so far")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
if numFail > maxFailures:
|
||||
logging.error("Too many failures! Test failed!")
|
||||
return False
|
||||
return True</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.test.subscribe"><code class="name flex">
|
||||
<span>def <span class="ident">subscribe</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Subscribe to the topics the user probably wants to see, prints output to stdout</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def subscribe():
|
||||
"""Subscribe to the topics the user probably wants to see, prints output to stdout"""
|
||||
|
||||
pub.subscribe(onNode, "meshtastic.node")</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.test.testAll"><code class="name flex">
|
||||
<span>def <span class="ident">testAll</span></span>(<span>numTests=5)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Run a series of tests using devices we can find.
|
||||
This is called from the cli with the "–test" option.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def testAll(numTests=5):
|
||||
"""
|
||||
Run a series of tests using devices we can find.
|
||||
This is called from the cli with the "--test" option.
|
||||
|
||||
"""
|
||||
ports = meshtastic.util.findPorts()
|
||||
if len(ports) < 2:
|
||||
meshtastic.util.our_exit("Warning: Must have at least two devices connected to USB.")
|
||||
|
||||
pub.subscribe(onConnection, "meshtastic.connection")
|
||||
pub.subscribe(onReceive, "meshtastic.receive")
|
||||
global interfaces
|
||||
interfaces = list(map(lambda port: SerialInterface(
|
||||
port, debugOut=openDebugLog(port), connectNow=True), ports))
|
||||
|
||||
logging.info("Ports opened, starting test")
|
||||
result = testThread(numTests)
|
||||
|
||||
for i in interfaces:
|
||||
i.close()
|
||||
|
||||
return result</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.test.testSend"><code class="name flex">
|
||||
<span>def <span class="ident">testSend</span></span>(<span>fromInterface, toInterface, isBroadcast=False, asBinary=False, wantAck=False)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Sends one test packet between two nodes and then returns success or failure</p>
|
||||
<h2 id="arguments">Arguments</h2>
|
||||
<p>fromInterface {[type]} – [description]
|
||||
toInterface {[type]} – [description]</p>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>boolean – True for success</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def testSend(fromInterface, toInterface, isBroadcast=False, asBinary=False, wantAck=False):
|
||||
"""
|
||||
Sends one test packet between two nodes and then returns success or failure
|
||||
|
||||
Arguments:
|
||||
fromInterface {[type]} -- [description]
|
||||
toInterface {[type]} -- [description]
|
||||
|
||||
Returns:
|
||||
boolean -- True for success
|
||||
"""
|
||||
global receivedPackets
|
||||
receivedPackets = []
|
||||
fromNode = fromInterface.myInfo.my_node_num
|
||||
|
||||
if isBroadcast:
|
||||
toNode = BROADCAST_NUM
|
||||
else:
|
||||
toNode = toInterface.myInfo.my_node_num
|
||||
|
||||
logging.debug(
|
||||
f"Sending test wantAck={wantAck} packet from {fromNode} to {toNode}")
|
||||
global sendingInterface
|
||||
sendingInterface = fromInterface
|
||||
if not asBinary:
|
||||
fromInterface.sendText(f"Test {testNumber}", toNode, wantAck=wantAck)
|
||||
else:
|
||||
fromInterface.sendData((f"Binary {testNumber}").encode(
|
||||
"utf-8"), toNode, wantAck=wantAck)
|
||||
for _ in range(60): # max of 60 secs before we timeout
|
||||
time.sleep(1)
|
||||
if len(receivedPackets) >= 1:
|
||||
return True
|
||||
return False # Failed to send</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.test.testSimulator"><code class="name flex">
|
||||
<span>def <span class="ident">testSimulator</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Assume that someone has launched meshtastic-native as a simulated node.
|
||||
Talk to that node over TCP, do some operations and if they are successful
|
||||
exit the process with a success code, else exit with a non zero exit code.</p>
|
||||
<p>Run with
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def testSimulator():
|
||||
"""
|
||||
Assume that someone has launched meshtastic-native as a simulated node.
|
||||
Talk to that node over TCP, do some operations and if they are successful
|
||||
exit the process with a success code, else exit with a non zero exit code.
|
||||
|
||||
Run with
|
||||
python3 -c 'from meshtastic.test import testSimulator; testSimulator()'
|
||||
"""
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.info("Connecting to simulator on localhost!")
|
||||
try:
|
||||
iface = TCPInterface("localhost")
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
iface.localNode.exitSimulator()
|
||||
iface.close()
|
||||
logging.info("Integration test successful!")
|
||||
except:
|
||||
print("Error while testing simulator:", sys.exc_info()[0])
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
sys.exit(0)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.test.testThread"><code class="name flex">
|
||||
<span>def <span class="ident">testThread</span></span>(<span>numTests=50)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test thread</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def testThread(numTests=50):
|
||||
"""Test thread"""
|
||||
logging.info("Found devices, starting tests...")
|
||||
result = runTests(numTests, wantAck=True)
|
||||
if result:
|
||||
# Run another test
|
||||
# Allow a few dropped packets
|
||||
result = runTests(numTests, wantAck=False, maxFailures=1)
|
||||
return result</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-variables">Global variables</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.test.interfaces" href="#meshtastic.test.interfaces">interfaces</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="two-column">
|
||||
<li><code><a title="meshtastic.test.onConnection" href="#meshtastic.test.onConnection">onConnection</a></code></li>
|
||||
<li><code><a title="meshtastic.test.onNode" href="#meshtastic.test.onNode">onNode</a></code></li>
|
||||
<li><code><a title="meshtastic.test.onReceive" href="#meshtastic.test.onReceive">onReceive</a></code></li>
|
||||
<li><code><a title="meshtastic.test.openDebugLog" href="#meshtastic.test.openDebugLog">openDebugLog</a></code></li>
|
||||
<li><code><a title="meshtastic.test.runTests" href="#meshtastic.test.runTests">runTests</a></code></li>
|
||||
<li><code><a title="meshtastic.test.subscribe" href="#meshtastic.test.subscribe">subscribe</a></code></li>
|
||||
<li><code><a title="meshtastic.test.testAll" href="#meshtastic.test.testAll">testAll</a></code></li>
|
||||
<li><code><a title="meshtastic.test.testSend" href="#meshtastic.test.testSend">testSend</a></code></li>
|
||||
<li><code><a title="meshtastic.test.testSimulator" href="#meshtastic.test.testSimulator">testSimulator</a></code></li>
|
||||
<li><code><a title="meshtastic.test.testThread" href="#meshtastic.test.testThread">testThread</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
199
docs/meshtastic/tests/conftest.html
Normal file
199
docs/meshtastic/tests/conftest.html
Normal file
@@ -0,0 +1,199 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.conftest API documentation</title>
|
||||
<meta name="description" content="Common pytest code (place for fixtures)." />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.conftest</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Common pytest code (place for fixtures).</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Common pytest code (place for fixtures)."""
|
||||
|
||||
import argparse
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
import pytest
|
||||
|
||||
from meshtastic.__main__ import Globals
|
||||
from ..mesh_interface import MeshInterface
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def reset_globals():
|
||||
"""Fixture to reset globals."""
|
||||
parser = None
|
||||
parser = argparse.ArgumentParser()
|
||||
Globals.getInstance().reset()
|
||||
Globals.getInstance().set_parser(parser)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def iface_with_nodes():
|
||||
"""Fixture to setup some nodes."""
|
||||
nodesById = {
|
||||
'!9388f81c': {
|
||||
'num': 2475227164,
|
||||
'user': {
|
||||
'id': '!9388f81c',
|
||||
'longName': 'Unknown f81c',
|
||||
'shortName': '?1C',
|
||||
'macaddr': 'RBeTiPgc',
|
||||
'hwModel': 'TBEAM'
|
||||
},
|
||||
'position': {},
|
||||
'lastHeard': 1640204888
|
||||
}
|
||||
}
|
||||
|
||||
nodesByNum = {
|
||||
2475227164: {
|
||||
'num': 2475227164,
|
||||
'user': {
|
||||
'id': '!9388f81c',
|
||||
'longName': 'Unknown f81c',
|
||||
'shortName': '?1C',
|
||||
'macaddr': 'RBeTiPgc',
|
||||
'hwModel': 'TBEAM'
|
||||
},
|
||||
'position': {
|
||||
'time': 1640206266
|
||||
},
|
||||
'lastHeard': 1640206266
|
||||
}
|
||||
}
|
||||
iface = MeshInterface(noProto=True)
|
||||
iface.nodes = nodesById
|
||||
iface.nodesByNum = nodesByNum
|
||||
myInfo = MagicMock()
|
||||
iface.myInfo = myInfo
|
||||
iface.myInfo.my_node_num = 2475227164
|
||||
return iface</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.conftest.iface_with_nodes"><code class="name flex">
|
||||
<span>def <span class="ident">iface_with_nodes</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Fixture to setup some nodes.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def iface_with_nodes():
|
||||
"""Fixture to setup some nodes."""
|
||||
nodesById = {
|
||||
'!9388f81c': {
|
||||
'num': 2475227164,
|
||||
'user': {
|
||||
'id': '!9388f81c',
|
||||
'longName': 'Unknown f81c',
|
||||
'shortName': '?1C',
|
||||
'macaddr': 'RBeTiPgc',
|
||||
'hwModel': 'TBEAM'
|
||||
},
|
||||
'position': {},
|
||||
'lastHeard': 1640204888
|
||||
}
|
||||
}
|
||||
|
||||
nodesByNum = {
|
||||
2475227164: {
|
||||
'num': 2475227164,
|
||||
'user': {
|
||||
'id': '!9388f81c',
|
||||
'longName': 'Unknown f81c',
|
||||
'shortName': '?1C',
|
||||
'macaddr': 'RBeTiPgc',
|
||||
'hwModel': 'TBEAM'
|
||||
},
|
||||
'position': {
|
||||
'time': 1640206266
|
||||
},
|
||||
'lastHeard': 1640206266
|
||||
}
|
||||
}
|
||||
iface = MeshInterface(noProto=True)
|
||||
iface.nodes = nodesById
|
||||
iface.nodesByNum = nodesByNum
|
||||
myInfo = MagicMock()
|
||||
iface.myInfo = myInfo
|
||||
iface.myInfo.my_node_num = 2475227164
|
||||
return iface</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.conftest.reset_globals"><code class="name flex">
|
||||
<span>def <span class="ident">reset_globals</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Fixture to reset globals.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def reset_globals():
|
||||
"""Fixture to reset globals."""
|
||||
parser = None
|
||||
parser = argparse.ArgumentParser()
|
||||
Globals.getInstance().reset()
|
||||
Globals.getInstance().set_parser(parser)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.conftest.iface_with_nodes" href="#meshtastic.tests.conftest.iface_with_nodes">iface_with_nodes</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.conftest.reset_globals" href="#meshtastic.tests.conftest.reset_globals">reset_globals</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
142
docs/meshtastic/tests/index.html
Normal file
142
docs/meshtastic/tests/index.html
Normal file
@@ -0,0 +1,142 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests API documentation</title>
|
||||
<meta name="description" content="" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-submodules">Sub-modules</h2>
|
||||
<dl>
|
||||
<dt><code class="name"><a title="meshtastic.tests.conftest" href="conftest.html">meshtastic.tests.conftest</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Common pytest code (place for fixtures).</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_ble_interface" href="test_ble_interface.html">meshtastic.tests.test_ble_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for ble_interface.py</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_examples" href="test_examples.html">meshtastic.tests.test_examples</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic test that the examples run as expected.
|
||||
We assume you have a python virtual environment in current directory.
|
||||
If not, you need to run: …</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_globals" href="test_globals.html">meshtastic.tests.test_globals</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for globals.py</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_int" href="test_int.html">meshtastic.tests.test_int</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic integration tests</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_main" href="test_main.html">meshtastic.tests.test_main</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for <strong>main</strong>.py</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_mesh_interface" href="test_mesh_interface.html">meshtastic.tests.test_mesh_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for mesh_interface.py</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_node" href="test_node.html">meshtastic.tests.test_node</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for node.py</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_remote_hardware" href="test_remote_hardware.html">meshtastic.tests.test_remote_hardware</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for remote_hardware.py</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_serial_interface" href="test_serial_interface.html">meshtastic.tests.test_serial_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for serial_interface.py</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_smoke1" href="test_smoke1.html">meshtastic.tests.test_smoke1</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic smoke tests with a single device via USB</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_smoke2" href="test_smoke2.html">meshtastic.tests.test_smoke2</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic smoke tests with 2 devices connected via USB</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_smoke_wifi" href="test_smoke_wifi.html">meshtastic.tests.test_smoke_wifi</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic smoke tests a device setup with wifi …</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_stream_interface" href="test_stream_interface.html">meshtastic.tests.test_stream_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for stream_interface.py</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_tcp_interface" href="test_tcp_interface.html">meshtastic.tests.test_tcp_interface</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for tcp_interface.py</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="meshtastic.tests.test_util" href="test_util.html">meshtastic.tests.test_util</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Meshtastic unit tests for util.py</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="../index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-submodules">Sub-modules</a></h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests.conftest" href="conftest.html">meshtastic.tests.conftest</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_ble_interface" href="test_ble_interface.html">meshtastic.tests.test_ble_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_examples" href="test_examples.html">meshtastic.tests.test_examples</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_globals" href="test_globals.html">meshtastic.tests.test_globals</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_int" href="test_int.html">meshtastic.tests.test_int</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_main" href="test_main.html">meshtastic.tests.test_main</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_mesh_interface" href="test_mesh_interface.html">meshtastic.tests.test_mesh_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_node" href="test_node.html">meshtastic.tests.test_node</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_remote_hardware" href="test_remote_hardware.html">meshtastic.tests.test_remote_hardware</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_serial_interface" href="test_serial_interface.html">meshtastic.tests.test_serial_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_smoke1" href="test_smoke1.html">meshtastic.tests.test_smoke1</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_smoke2" href="test_smoke2.html">meshtastic.tests.test_smoke2</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_smoke_wifi" href="test_smoke_wifi.html">meshtastic.tests.test_smoke_wifi</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_stream_interface" href="test_stream_interface.html">meshtastic.tests.test_stream_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_tcp_interface" href="test_tcp_interface.html">meshtastic.tests.test_tcp_interface</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util" href="test_util.html">meshtastic.tests.test_util</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
95
docs/meshtastic/tests/test_ble_interface.html
Normal file
95
docs/meshtastic/tests/test_ble_interface.html
Normal file
@@ -0,0 +1,95 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_ble_interface API documentation</title>
|
||||
<meta name="description" content="Meshtastic unit tests for ble_interface.py" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_ble_interface</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic unit tests for ble_interface.py</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic unit tests for ble_interface.py"""
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
from ..ble_interface import BLEInterface
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_BLEInterface():
|
||||
"""Test that we can instantiate a BLEInterface"""
|
||||
iface = BLEInterface('foo', debugOut=True, noProto=True)
|
||||
iface.close()</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_ble_interface.test_BLEInterface"><code class="name flex">
|
||||
<span>def <span class="ident">test_BLEInterface</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can instantiate a BLEInterface</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_BLEInterface():
|
||||
"""Test that we can instantiate a BLEInterface"""
|
||||
iface = BLEInterface('foo', debugOut=True, noProto=True)
|
||||
iface.close()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_ble_interface.test_BLEInterface" href="#meshtastic.tests.test_ble_interface.test_BLEInterface">test_BLEInterface</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
132
docs/meshtastic/tests/test_examples.html
Normal file
132
docs/meshtastic/tests/test_examples.html
Normal file
@@ -0,0 +1,132 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_examples API documentation</title>
|
||||
<meta name="description" content="Meshtastic test that the examples run as expected.
|
||||
We assume you have a python virtual environment in current directory.
|
||||
If not, you need to run: …" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_examples</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic test that the examples run as expected.
|
||||
We assume you have a python virtual environment in current directory.
|
||||
If not, you need to run: "python3 -m venv venv", "source venv/bin/activate", "pip install ."</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic test that the examples run as expected.
|
||||
We assume you have a python virtual environment in current directory.
|
||||
If not, you need to run: "python3 -m venv venv", "source venv/bin/activate", "pip install ."
|
||||
"""
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
@pytest.mark.examples
|
||||
def test_examples_hello_world_serial_no_arg():
|
||||
"""Test hello_world_serial without any args"""
|
||||
return_value, _ = subprocess.getstatusoutput('source venv/bin/activate; python3 examples/hello_world_serial.py')
|
||||
assert return_value == 3
|
||||
|
||||
|
||||
@pytest.mark.examples
|
||||
def test_examples_hello_world_serial_with_arg(capsys):
|
||||
"""Test hello_world_serial with arg"""
|
||||
return_value, _ = subprocess.getstatusoutput('source venv/bin/activate; python3 examples/hello_world_serial.py hello')
|
||||
assert return_value == 1
|
||||
_, err = capsys.readouterr()
|
||||
assert err == ''
|
||||
# TODO: Why does this not work?
|
||||
# assert out == 'Warning: No Meshtastic devices detected.'</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_examples.test_examples_hello_world_serial_no_arg"><code class="name flex">
|
||||
<span>def <span class="ident">test_examples_hello_world_serial_no_arg</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test hello_world_serial without any args</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.examples
|
||||
def test_examples_hello_world_serial_no_arg():
|
||||
"""Test hello_world_serial without any args"""
|
||||
return_value, _ = subprocess.getstatusoutput('source venv/bin/activate; python3 examples/hello_world_serial.py')
|
||||
assert return_value == 3</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_examples.test_examples_hello_world_serial_with_arg"><code class="name flex">
|
||||
<span>def <span class="ident">test_examples_hello_world_serial_with_arg</span></span>(<span>capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test hello_world_serial with arg</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.examples
|
||||
def test_examples_hello_world_serial_with_arg(capsys):
|
||||
"""Test hello_world_serial with arg"""
|
||||
return_value, _ = subprocess.getstatusoutput('source venv/bin/activate; python3 examples/hello_world_serial.py hello')
|
||||
assert return_value == 1
|
||||
_, err = capsys.readouterr()
|
||||
assert err == ''
|
||||
# TODO: Why does this not work?
|
||||
# assert out == 'Warning: No Meshtastic devices detected.'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_examples.test_examples_hello_world_serial_no_arg" href="#meshtastic.tests.test_examples.test_examples_hello_world_serial_no_arg">test_examples_hello_world_serial_no_arg</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_examples.test_examples_hello_world_serial_with_arg" href="#meshtastic.tests.test_examples.test_examples_hello_world_serial_with_arg">test_examples_hello_world_serial_with_arg</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
130
docs/meshtastic/tests/test_globals.html
Normal file
130
docs/meshtastic/tests/test_globals.html
Normal file
@@ -0,0 +1,130 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_globals API documentation</title>
|
||||
<meta name="description" content="Meshtastic unit tests for globals.py" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_globals</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic unit tests for globals.py</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic unit tests for globals.py
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from ..globals import Globals
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_globals_get_instaance():
|
||||
"""Test that we can instantiate a Globals instance"""
|
||||
ourglobals = Globals.getInstance()
|
||||
ourglobals2 = Globals.getInstance()
|
||||
assert ourglobals == ourglobals2
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_globals_there_can_be_only_one():
|
||||
"""Test that we can cannot create two Globals instances"""
|
||||
# if we have an instance, delete it
|
||||
Globals.getInstance()
|
||||
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||
# try to create another instance
|
||||
Globals()
|
||||
assert pytest_wrapped_e.type == Exception</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_globals.test_globals_get_instaance"><code class="name flex">
|
||||
<span>def <span class="ident">test_globals_get_instaance</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can instantiate a Globals instance</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_globals_get_instaance():
|
||||
"""Test that we can instantiate a Globals instance"""
|
||||
ourglobals = Globals.getInstance()
|
||||
ourglobals2 = Globals.getInstance()
|
||||
assert ourglobals == ourglobals2</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_globals.test_globals_there_can_be_only_one"><code class="name flex">
|
||||
<span>def <span class="ident">test_globals_there_can_be_only_one</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can cannot create two Globals instances</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_globals_there_can_be_only_one():
|
||||
"""Test that we can cannot create two Globals instances"""
|
||||
# if we have an instance, delete it
|
||||
Globals.getInstance()
|
||||
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||
# try to create another instance
|
||||
Globals()
|
||||
assert pytest_wrapped_e.type == Exception</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_globals.test_globals_get_instaance" href="#meshtastic.tests.test_globals.test_globals_get_instaance">test_globals_get_instaance</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_globals.test_globals_there_can_be_only_one" href="#meshtastic.tests.test_globals.test_globals_there_can_be_only_one">test_globals_there_can_be_only_one</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
177
docs/meshtastic/tests/test_int.html
Normal file
177
docs/meshtastic/tests/test_int.html
Normal file
@@ -0,0 +1,177 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_int API documentation</title>
|
||||
<meta name="description" content="Meshtastic integration tests" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_int</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic integration tests</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic integration tests"""
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.int
|
||||
def test_int_no_args():
|
||||
"""Test without any args"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic')
|
||||
assert re.match(r'usage: meshtastic', out)
|
||||
assert return_value == 1
|
||||
|
||||
|
||||
@pytest.mark.int
|
||||
def test_int_version():
|
||||
"""Test '--version'."""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --version')
|
||||
assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.int
|
||||
def test_int_help():
|
||||
"""Test '--help'."""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --help')
|
||||
assert re.match(r'usage: meshtastic ', out)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
@pytest.mark.int
|
||||
def test_int_support():
|
||||
"""Test '--support'."""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --support')
|
||||
assert re.search(r'System', out)
|
||||
assert re.search(r'Python', out)
|
||||
assert return_value == 0</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_int.test_int_help"><code class="name flex">
|
||||
<span>def <span class="ident">test_int_help</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test '–help'.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.int
|
||||
def test_int_help():
|
||||
"""Test '--help'."""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --help')
|
||||
assert re.match(r'usage: meshtastic ', out)
|
||||
assert return_value == 0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_int.test_int_no_args"><code class="name flex">
|
||||
<span>def <span class="ident">test_int_no_args</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test without any args</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.int
|
||||
def test_int_no_args():
|
||||
"""Test without any args"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic')
|
||||
assert re.match(r'usage: meshtastic', out)
|
||||
assert return_value == 1</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_int.test_int_support"><code class="name flex">
|
||||
<span>def <span class="ident">test_int_support</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test '–support'.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.int
|
||||
def test_int_support():
|
||||
"""Test '--support'."""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --support')
|
||||
assert re.search(r'System', out)
|
||||
assert re.search(r'Python', out)
|
||||
assert return_value == 0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_int.test_int_version"><code class="name flex">
|
||||
<span>def <span class="ident">test_int_version</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test '–version'.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.int
|
||||
def test_int_version():
|
||||
"""Test '--version'."""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --version')
|
||||
assert re.match(r'[0-9]+\.[0-9]+\.[0-9]', out)
|
||||
assert return_value == 0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_int.test_int_help" href="#meshtastic.tests.test_int.test_int_help">test_int_help</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_int.test_int_no_args" href="#meshtastic.tests.test_int.test_int_no_args">test_int_no_args</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_int.test_int_support" href="#meshtastic.tests.test_int.test_int_support">test_int_support</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_int.test_int_version" href="#meshtastic.tests.test_int.test_int_version">test_int_version</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
4552
docs/meshtastic/tests/test_main.html
Normal file
4552
docs/meshtastic/tests/test_main.html
Normal file
File diff suppressed because it is too large
Load Diff
1290
docs/meshtastic/tests/test_mesh_interface.html
Normal file
1290
docs/meshtastic/tests/test_mesh_interface.html
Normal file
File diff suppressed because it is too large
Load Diff
4143
docs/meshtastic/tests/test_node.html
Normal file
4143
docs/meshtastic/tests/test_node.html
Normal file
File diff suppressed because it is too large
Load Diff
304
docs/meshtastic/tests/test_remote_hardware.html
Normal file
304
docs/meshtastic/tests/test_remote_hardware.html
Normal file
@@ -0,0 +1,304 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_remote_hardware API documentation</title>
|
||||
<meta name="description" content="Meshtastic unit tests for remote_hardware.py" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_remote_hardware</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic unit tests for remote_hardware.py</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic unit tests for remote_hardware.py"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from unittest.mock import patch, MagicMock
|
||||
import pytest
|
||||
|
||||
from ..remote_hardware import RemoteHardwareClient, onGPIOreceive
|
||||
from ..serial_interface import SerialInterface
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_RemoteHardwareClient():
|
||||
"""Test that we can instantiate a RemoteHardwareClient instance"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
rhw = RemoteHardwareClient(iface)
|
||||
assert rhw.iface == iface
|
||||
iface.close()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_onGPIOreceive(capsys):
|
||||
"""Test onGPIOreceive"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
packet = {'decoded': {'remotehw': {'typ': 'foo', 'gpioValue': '4096' }}}
|
||||
onGPIOreceive(packet, iface)
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Received RemoteHardware', out)
|
||||
assert err == ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_RemoteHardwareClient_no_gpio_channel(capsys):
|
||||
"""Test that we can instantiate a RemoteHardwareClient instance but there is no channel named channel 'gpio'"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
||||
mo.localNode.getChannelByName.return_value = None
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
RemoteHardwareClient(mo)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Warning: No channel named', out)
|
||||
assert err == ""
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_readGPIOs(caplog):
|
||||
"""Test readGPIOs"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
rhw = RemoteHardwareClient(iface)
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
rhw.readGPIOs('0x10', 123)
|
||||
assert re.search(r'readGPIOs', caplog.text, re.MULTILINE)
|
||||
iface.close()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_writeGPIOs(caplog):
|
||||
"""Test writeGPIOs"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
rhw = RemoteHardwareClient(iface)
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
rhw.writeGPIOs('0x10', 123, 1)
|
||||
assert re.search(r'writeGPIOs', caplog.text, re.MULTILINE)
|
||||
iface.close()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_watchGPIOs(caplog):
|
||||
"""Test watchGPIOs"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
rhw = RemoteHardwareClient(iface)
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
rhw.watchGPIOs('0x10', 123)
|
||||
assert re.search(r'watchGPIOs', caplog.text, re.MULTILINE)
|
||||
iface.close()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_sendHardware_no_nodeid():
|
||||
"""Test sending no nodeid to _sendHardware()"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
rhw = RemoteHardwareClient(mo)
|
||||
rhw._sendHardware(None, None)
|
||||
assert pytest_wrapped_e.type == SystemExit</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_remote_hardware.test_RemoteHardwareClient"><code class="name flex">
|
||||
<span>def <span class="ident">test_RemoteHardwareClient</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can instantiate a RemoteHardwareClient instance</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_RemoteHardwareClient():
|
||||
"""Test that we can instantiate a RemoteHardwareClient instance"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
rhw = RemoteHardwareClient(iface)
|
||||
assert rhw.iface == iface
|
||||
iface.close()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_remote_hardware.test_RemoteHardwareClient_no_gpio_channel"><code class="name flex">
|
||||
<span>def <span class="ident">test_RemoteHardwareClient_no_gpio_channel</span></span>(<span>capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can instantiate a RemoteHardwareClient instance but there is no channel named channel 'gpio'</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_RemoteHardwareClient_no_gpio_channel(capsys):
|
||||
"""Test that we can instantiate a RemoteHardwareClient instance but there is no channel named channel 'gpio'"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
||||
mo.localNode.getChannelByName.return_value = None
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
RemoteHardwareClient(mo)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Warning: No channel named', out)
|
||||
assert err == ""</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_remote_hardware.test_onGPIOreceive"><code class="name flex">
|
||||
<span>def <span class="ident">test_onGPIOreceive</span></span>(<span>capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test onGPIOreceive</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_onGPIOreceive(capsys):
|
||||
"""Test onGPIOreceive"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
packet = {'decoded': {'remotehw': {'typ': 'foo', 'gpioValue': '4096' }}}
|
||||
onGPIOreceive(packet, iface)
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Received RemoteHardware', out)
|
||||
assert err == ''</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_remote_hardware.test_readGPIOs"><code class="name flex">
|
||||
<span>def <span class="ident">test_readGPIOs</span></span>(<span>caplog)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test readGPIOs</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_readGPIOs(caplog):
|
||||
"""Test readGPIOs"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
rhw = RemoteHardwareClient(iface)
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
rhw.readGPIOs('0x10', 123)
|
||||
assert re.search(r'readGPIOs', caplog.text, re.MULTILINE)
|
||||
iface.close()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_remote_hardware.test_sendHardware_no_nodeid"><code class="name flex">
|
||||
<span>def <span class="ident">test_sendHardware_no_nodeid</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test sending no nodeid to _sendHardware()</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_sendHardware_no_nodeid():
|
||||
"""Test sending no nodeid to _sendHardware()"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
with patch('meshtastic.serial_interface.SerialInterface', return_value=iface) as mo:
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
rhw = RemoteHardwareClient(mo)
|
||||
rhw._sendHardware(None, None)
|
||||
assert pytest_wrapped_e.type == SystemExit</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_remote_hardware.test_watchGPIOs"><code class="name flex">
|
||||
<span>def <span class="ident">test_watchGPIOs</span></span>(<span>caplog)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test watchGPIOs</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_watchGPIOs(caplog):
|
||||
"""Test watchGPIOs"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
rhw = RemoteHardwareClient(iface)
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
rhw.watchGPIOs('0x10', 123)
|
||||
assert re.search(r'watchGPIOs', caplog.text, re.MULTILINE)
|
||||
iface.close()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_remote_hardware.test_writeGPIOs"><code class="name flex">
|
||||
<span>def <span class="ident">test_writeGPIOs</span></span>(<span>caplog)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test writeGPIOs</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_writeGPIOs(caplog):
|
||||
"""Test writeGPIOs"""
|
||||
iface = MagicMock(autospec=SerialInterface)
|
||||
rhw = RemoteHardwareClient(iface)
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
rhw.writeGPIOs('0x10', 123, 1)
|
||||
assert re.search(r'writeGPIOs', caplog.text, re.MULTILINE)
|
||||
iface.close()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_remote_hardware.test_RemoteHardwareClient" href="#meshtastic.tests.test_remote_hardware.test_RemoteHardwareClient">test_RemoteHardwareClient</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_remote_hardware.test_RemoteHardwareClient_no_gpio_channel" href="#meshtastic.tests.test_remote_hardware.test_RemoteHardwareClient_no_gpio_channel">test_RemoteHardwareClient_no_gpio_channel</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_remote_hardware.test_onGPIOreceive" href="#meshtastic.tests.test_remote_hardware.test_onGPIOreceive">test_onGPIOreceive</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_remote_hardware.test_readGPIOs" href="#meshtastic.tests.test_remote_hardware.test_readGPIOs">test_readGPIOs</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_remote_hardware.test_sendHardware_no_nodeid" href="#meshtastic.tests.test_remote_hardware.test_sendHardware_no_nodeid">test_sendHardware_no_nodeid</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_remote_hardware.test_watchGPIOs" href="#meshtastic.tests.test_remote_hardware.test_watchGPIOs">test_watchGPIOs</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_remote_hardware.test_writeGPIOs" href="#meshtastic.tests.test_remote_hardware.test_writeGPIOs">test_writeGPIOs</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
186
docs/meshtastic/tests/test_serial_interface.html
Normal file
186
docs/meshtastic/tests/test_serial_interface.html
Normal file
@@ -0,0 +1,186 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_serial_interface API documentation</title>
|
||||
<meta name="description" content="Meshtastic unit tests for serial_interface.py" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_serial_interface</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic unit tests for serial_interface.py</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic unit tests for serial_interface.py"""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from ..serial_interface import SerialInterface
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch('serial.Serial')
|
||||
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyUSBfake'])
|
||||
def test_SerialInterface_single_port(mocked_findPorts, mocked_serial):
|
||||
"""Test that we can instantiate a SerialInterface with a single port"""
|
||||
iface = SerialInterface(noProto=True)
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
iface.close()
|
||||
mocked_findPorts.assert_called()
|
||||
mocked_serial.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch('meshtastic.util.findPorts', return_value=[])
|
||||
def test_SerialInterface_no_ports(mocked_findPorts, capsys):
|
||||
"""Test that we can instantiate a SerialInterface with no ports"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
SerialInterface(noProto=True)
|
||||
mocked_findPorts.assert_called()
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Warning: No Meshtastic devices detected', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyUSBfake1', '/dev/ttyUSBfake2'])
|
||||
def test_SerialInterface_multiple_ports(mocked_findPorts, capsys):
|
||||
"""Test that we can instantiate a SerialInterface with two ports"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
SerialInterface(noProto=True)
|
||||
mocked_findPorts.assert_called()
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Warning: Multiple serial ports were detected', out, re.MULTILINE)
|
||||
assert err == ''</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_serial_interface.test_SerialInterface_multiple_ports"><code class="name flex">
|
||||
<span>def <span class="ident">test_SerialInterface_multiple_ports</span></span>(<span>mocked_findPorts, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can instantiate a SerialInterface with two ports</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyUSBfake1', '/dev/ttyUSBfake2'])
|
||||
def test_SerialInterface_multiple_ports(mocked_findPorts, capsys):
|
||||
"""Test that we can instantiate a SerialInterface with two ports"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
SerialInterface(noProto=True)
|
||||
mocked_findPorts.assert_called()
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Warning: Multiple serial ports were detected', out, re.MULTILINE)
|
||||
assert err == ''</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_serial_interface.test_SerialInterface_no_ports"><code class="name flex">
|
||||
<span>def <span class="ident">test_SerialInterface_no_ports</span></span>(<span>mocked_findPorts, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can instantiate a SerialInterface with no ports</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
@patch('meshtastic.util.findPorts', return_value=[])
|
||||
def test_SerialInterface_no_ports(mocked_findPorts, capsys):
|
||||
"""Test that we can instantiate a SerialInterface with no ports"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
SerialInterface(noProto=True)
|
||||
mocked_findPorts.assert_called()
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Warning: No Meshtastic devices detected', out, re.MULTILINE)
|
||||
assert err == ''</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_serial_interface.test_SerialInterface_single_port"><code class="name flex">
|
||||
<span>def <span class="ident">test_SerialInterface_single_port</span></span>(<span>mocked_findPorts, mocked_serial)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can instantiate a SerialInterface with a single port</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
@patch('serial.Serial')
|
||||
@patch('meshtastic.util.findPorts', return_value=['/dev/ttyUSBfake'])
|
||||
def test_SerialInterface_single_port(mocked_findPorts, mocked_serial):
|
||||
"""Test that we can instantiate a SerialInterface with a single port"""
|
||||
iface = SerialInterface(noProto=True)
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
iface.close()
|
||||
mocked_findPorts.assert_called()
|
||||
mocked_serial.assert_called()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_serial_interface.test_SerialInterface_multiple_ports" href="#meshtastic.tests.test_serial_interface.test_SerialInterface_multiple_ports">test_SerialInterface_multiple_ports</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_serial_interface.test_SerialInterface_no_ports" href="#meshtastic.tests.test_serial_interface.test_SerialInterface_no_ports">test_SerialInterface_no_ports</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_serial_interface.test_SerialInterface_single_port" href="#meshtastic.tests.test_serial_interface.test_SerialInterface_single_port">test_SerialInterface_single_port</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
1822
docs/meshtastic/tests/test_smoke1.html
Normal file
1822
docs/meshtastic/tests/test_smoke1.html
Normal file
File diff suppressed because it is too large
Load Diff
127
docs/meshtastic/tests/test_smoke2.html
Normal file
127
docs/meshtastic/tests/test_smoke2.html
Normal file
@@ -0,0 +1,127 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_smoke2 API documentation</title>
|
||||
<meta name="description" content="Meshtastic smoke tests with 2 devices connected via USB" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_smoke2</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic smoke tests with 2 devices connected via USB</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic smoke tests with 2 devices connected via USB"""
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.smoke2
|
||||
def test_smoke2_info():
|
||||
"""Test --info with 2 devices connected serially"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'Warning: Multiple', out, re.MULTILINE)
|
||||
assert return_value == 1
|
||||
|
||||
|
||||
@pytest.mark.smoke2
|
||||
def test_smoke2_test():
|
||||
"""Test --test"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --test')
|
||||
assert re.search(r'Writing serial debugging', out, re.MULTILINE)
|
||||
assert re.search(r'Ports opened', out, re.MULTILINE)
|
||||
assert re.search(r'Running 5 tests', out, re.MULTILINE)
|
||||
assert return_value == 0</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_smoke2.test_smoke2_info"><code class="name flex">
|
||||
<span>def <span class="ident">test_smoke2_info</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test –info with 2 devices connected serially</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.smoke2
|
||||
def test_smoke2_info():
|
||||
"""Test --info with 2 devices connected serially"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info')
|
||||
assert re.search(r'Warning: Multiple', out, re.MULTILINE)
|
||||
assert return_value == 1</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_smoke2.test_smoke2_test"><code class="name flex">
|
||||
<span>def <span class="ident">test_smoke2_test</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test –test</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.smoke2
|
||||
def test_smoke2_test():
|
||||
"""Test --test"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --test')
|
||||
assert re.search(r'Writing serial debugging', out, re.MULTILINE)
|
||||
assert re.search(r'Ports opened', out, re.MULTILINE)
|
||||
assert re.search(r'Running 5 tests', out, re.MULTILINE)
|
||||
assert return_value == 0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_smoke2.test_smoke2_info" href="#meshtastic.tests.test_smoke2.test_smoke2_info">test_smoke2_info</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_smoke2.test_smoke2_test" href="#meshtastic.tests.test_smoke2.test_smoke2_test">test_smoke2_test</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
115
docs/meshtastic/tests/test_smoke_wifi.html
Normal file
115
docs/meshtastic/tests/test_smoke_wifi.html
Normal file
@@ -0,0 +1,115 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_smoke_wifi API documentation</title>
|
||||
<meta name="description" content="Meshtastic smoke tests a device setup with wifi …" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_smoke_wifi</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic smoke tests a device setup with wifi.</p>
|
||||
<p>Need to have run the following on an esp32 device:
|
||||
meshtastic –set wifi_ssid 'foo' –set wifi_password 'sekret'</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic smoke tests a device setup with wifi.
|
||||
|
||||
Need to have run the following on an esp32 device:
|
||||
meshtastic --set wifi_ssid 'foo' --set wifi_password 'sekret'
|
||||
"""
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.smokewifi
|
||||
def test_smokewifi_info():
|
||||
"""Test --info"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info --host meshtastic.local')
|
||||
assert re.search(r'^Owner', out, re.MULTILINE)
|
||||
assert re.search(r'^My info', out, re.MULTILINE)
|
||||
assert re.search(r'^Nodes in mesh', out, re.MULTILINE)
|
||||
assert re.search(r'^Preferences', out, re.MULTILINE)
|
||||
assert re.search(r'^Channels', out, re.MULTILINE)
|
||||
assert re.search(r'^ PRIMARY', out, re.MULTILINE)
|
||||
assert re.search(r'^Primary channel URL', out, re.MULTILINE)
|
||||
assert return_value == 0</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_smoke_wifi.test_smokewifi_info"><code class="name flex">
|
||||
<span>def <span class="ident">test_smokewifi_info</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test –info</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.smokewifi
|
||||
def test_smokewifi_info():
|
||||
"""Test --info"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --info --host meshtastic.local')
|
||||
assert re.search(r'^Owner', out, re.MULTILINE)
|
||||
assert re.search(r'^My info', out, re.MULTILINE)
|
||||
assert re.search(r'^Nodes in mesh', out, re.MULTILINE)
|
||||
assert re.search(r'^Preferences', out, re.MULTILINE)
|
||||
assert re.search(r'^Channels', out, re.MULTILINE)
|
||||
assert re.search(r'^ PRIMARY', out, re.MULTILINE)
|
||||
assert re.search(r'^Primary channel URL', out, re.MULTILINE)
|
||||
assert return_value == 0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_smoke_wifi.test_smokewifi_info" href="#meshtastic.tests.test_smoke_wifi.test_smokewifi_info">test_smokewifi_info</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
246
docs/meshtastic/tests/test_stream_interface.html
Normal file
246
docs/meshtastic/tests/test_stream_interface.html
Normal file
@@ -0,0 +1,246 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_stream_interface API documentation</title>
|
||||
<meta name="description" content="Meshtastic unit tests for stream_interface.py" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_stream_interface</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic unit tests for stream_interface.py</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic unit tests for stream_interface.py"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
import pytest
|
||||
|
||||
from ..stream_interface import StreamInterface
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_StreamInterface():
|
||||
"""Test that we cannot instantiate a StreamInterface based on noProto"""
|
||||
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||
StreamInterface()
|
||||
assert pytest_wrapped_e.type == Exception
|
||||
|
||||
|
||||
# Note: This takes a bit, so moving from unit to slow
|
||||
@pytest.mark.unitslow
|
||||
def test_StreamInterface_with_noProto(caplog, reset_globals):
|
||||
"""Test that we can instantiate a StreamInterface based on nonProto
|
||||
and we can read/write bytes from a mocked stream
|
||||
"""
|
||||
stream = MagicMock()
|
||||
test_data = b'hello'
|
||||
stream.read.return_value = test_data
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
iface = StreamInterface(noProto=True, connectNow=False)
|
||||
iface.stream = stream
|
||||
iface._writeBytes(test_data)
|
||||
data = iface._readBytes(len(test_data))
|
||||
assert data == test_data
|
||||
|
||||
|
||||
# Note: This takes a bit, so moving from unit to slow
|
||||
# Tip: If you want to see the print output, run with '-s' flag:
|
||||
# pytest -s meshtastic/tests/test_stream_interface.py::test_sendToRadioImpl
|
||||
@pytest.mark.unitslow
|
||||
def test_sendToRadioImpl(caplog, reset_globals):
|
||||
"""Test _sendToRadioImpl()"""
|
||||
|
||||
# def add_header(b):
|
||||
# """Add header stuffs for radio"""
|
||||
# bufLen = len(b)
|
||||
# header = bytes([START1, START2, (bufLen >> 8) & 0xff, bufLen & 0xff])
|
||||
# return header + b
|
||||
|
||||
# captured raw bytes of a Heltec2.1 radio with 2 channels (primary and a secondary channel named "gpio")
|
||||
raw_1_my_info = b'\x1a,\x08\xdc\x8c\xd5\xc5\x02\x18\r2\x0e1.2.49.5354c49P\x15]\xe1%\x17Eh\xe0\xa7\x12p\xe8\x9d\x01x\x08\x90\x01\x01'
|
||||
raw_2_node_info = b'"9\x08\xdc\x8c\xd5\xc5\x02\x12(\n\t!28b5465c\x12\x0cUnknown 465c\x1a\x03?5C"\x06$o(\xb5F\\0\n\x1a\x02 1%M<\xc6a'
|
||||
# pylint: disable=C0301
|
||||
raw_3_node_info = b'"C\x08\xa4\x8c\xd5\xc5\x02\x12(\n\t!28b54624\x12\x0cUnknown 4624\x1a\x03?24"\x06$o(\xb5F$0\n\x1a\x07 5MH<\xc6a%G<\xc6a=\x00\x00\xc0@'
|
||||
raw_4_complete = b'@\xcf\xe5\xd1\x8c\x0e'
|
||||
# pylint: disable=C0301
|
||||
raw_5_prefs = b'Z6\r\\F\xb5(\x15\\F\xb5("\x1c\x08\x06\x12\x13*\x11\n\x0f0\x84\x07P\xac\x02\x88\x01\x01\xb0\t#\xb8\t\x015]$\xddk5\xd5\x7f!b=M<\xc6aP\x03`F'
|
||||
# pylint: disable=C0301
|
||||
raw_6_channel0 = b'Z.\r\\F\xb5(\x15\\F\xb5("\x14\x08\x06\x12\x0b:\t\x12\x05\x18\x01"\x01\x01\x18\x015^$\xddk5\xd6\x7f!b=M<\xc6aP\x03`F'
|
||||
# pylint: disable=C0301
|
||||
raw_7_channel1 = b'ZS\r\\F\xb5(\x15\\F\xb5("9\x08\x06\x120:.\x08\x01\x12(" \xb4&\xb3\xc7\x06\xd8\xe39%\xba\xa5\xee\x8eH\x06\xf6\xf4H\xe8\xd5\xc1[ao\xb5Y\\\xb4"\xafmi*\x04gpio\x18\x025_$\xddk5\xd7\x7f!b=M<\xc6aP\x03`F'
|
||||
raw_8_channel2 = b'Z)\r\\F\xb5(\x15\\F\xb5("\x0f\x08\x06\x12\x06:\x04\x08\x02\x12\x005`$\xddk5\xd8\x7f!b=M<\xc6aP\x03`F'
|
||||
raw_blank = b''
|
||||
|
||||
test_data = b'hello'
|
||||
stream = MagicMock()
|
||||
#stream.read.return_value = add_header(test_data)
|
||||
stream.read.side_effect = [ raw_1_my_info, raw_2_node_info, raw_3_node_info, raw_4_complete,
|
||||
raw_5_prefs, raw_6_channel0, raw_7_channel1, raw_8_channel2,
|
||||
raw_blank, raw_blank]
|
||||
toRadio = MagicMock()
|
||||
toRadio.SerializeToString.return_value = test_data
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
iface = StreamInterface(noProto=True, connectNow=False)
|
||||
iface.stream = stream
|
||||
iface.connect()
|
||||
iface._sendToRadioImpl(toRadio)
|
||||
assert re.search(r'Sending: ', caplog.text, re.MULTILINE)
|
||||
assert re.search(r'reading character', caplog.text, re.MULTILINE)
|
||||
assert re.search(r'In reader loop', caplog.text, re.MULTILINE)
|
||||
print(caplog.text)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_stream_interface.test_StreamInterface"><code class="name flex">
|
||||
<span>def <span class="ident">test_StreamInterface</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we cannot instantiate a StreamInterface based on noProto</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_StreamInterface():
|
||||
"""Test that we cannot instantiate a StreamInterface based on noProto"""
|
||||
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||
StreamInterface()
|
||||
assert pytest_wrapped_e.type == Exception</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_stream_interface.test_StreamInterface_with_noProto"><code class="name flex">
|
||||
<span>def <span class="ident">test_StreamInterface_with_noProto</span></span>(<span>caplog, reset_globals)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can instantiate a StreamInterface based on nonProto
|
||||
and we can read/write bytes from a mocked stream</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unitslow
|
||||
def test_StreamInterface_with_noProto(caplog, reset_globals):
|
||||
"""Test that we can instantiate a StreamInterface based on nonProto
|
||||
and we can read/write bytes from a mocked stream
|
||||
"""
|
||||
stream = MagicMock()
|
||||
test_data = b'hello'
|
||||
stream.read.return_value = test_data
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
iface = StreamInterface(noProto=True, connectNow=False)
|
||||
iface.stream = stream
|
||||
iface._writeBytes(test_data)
|
||||
data = iface._readBytes(len(test_data))
|
||||
assert data == test_data</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_stream_interface.test_sendToRadioImpl"><code class="name flex">
|
||||
<span>def <span class="ident">test_sendToRadioImpl</span></span>(<span>caplog, reset_globals)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test _sendToRadioImpl()</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unitslow
|
||||
def test_sendToRadioImpl(caplog, reset_globals):
|
||||
"""Test _sendToRadioImpl()"""
|
||||
|
||||
# def add_header(b):
|
||||
# """Add header stuffs for radio"""
|
||||
# bufLen = len(b)
|
||||
# header = bytes([START1, START2, (bufLen >> 8) & 0xff, bufLen & 0xff])
|
||||
# return header + b
|
||||
|
||||
# captured raw bytes of a Heltec2.1 radio with 2 channels (primary and a secondary channel named "gpio")
|
||||
raw_1_my_info = b'\x1a,\x08\xdc\x8c\xd5\xc5\x02\x18\r2\x0e1.2.49.5354c49P\x15]\xe1%\x17Eh\xe0\xa7\x12p\xe8\x9d\x01x\x08\x90\x01\x01'
|
||||
raw_2_node_info = b'"9\x08\xdc\x8c\xd5\xc5\x02\x12(\n\t!28b5465c\x12\x0cUnknown 465c\x1a\x03?5C"\x06$o(\xb5F\\0\n\x1a\x02 1%M<\xc6a'
|
||||
# pylint: disable=C0301
|
||||
raw_3_node_info = b'"C\x08\xa4\x8c\xd5\xc5\x02\x12(\n\t!28b54624\x12\x0cUnknown 4624\x1a\x03?24"\x06$o(\xb5F$0\n\x1a\x07 5MH<\xc6a%G<\xc6a=\x00\x00\xc0@'
|
||||
raw_4_complete = b'@\xcf\xe5\xd1\x8c\x0e'
|
||||
# pylint: disable=C0301
|
||||
raw_5_prefs = b'Z6\r\\F\xb5(\x15\\F\xb5("\x1c\x08\x06\x12\x13*\x11\n\x0f0\x84\x07P\xac\x02\x88\x01\x01\xb0\t#\xb8\t\x015]$\xddk5\xd5\x7f!b=M<\xc6aP\x03`F'
|
||||
# pylint: disable=C0301
|
||||
raw_6_channel0 = b'Z.\r\\F\xb5(\x15\\F\xb5("\x14\x08\x06\x12\x0b:\t\x12\x05\x18\x01"\x01\x01\x18\x015^$\xddk5\xd6\x7f!b=M<\xc6aP\x03`F'
|
||||
# pylint: disable=C0301
|
||||
raw_7_channel1 = b'ZS\r\\F\xb5(\x15\\F\xb5("9\x08\x06\x120:.\x08\x01\x12(" \xb4&\xb3\xc7\x06\xd8\xe39%\xba\xa5\xee\x8eH\x06\xf6\xf4H\xe8\xd5\xc1[ao\xb5Y\\\xb4"\xafmi*\x04gpio\x18\x025_$\xddk5\xd7\x7f!b=M<\xc6aP\x03`F'
|
||||
raw_8_channel2 = b'Z)\r\\F\xb5(\x15\\F\xb5("\x0f\x08\x06\x12\x06:\x04\x08\x02\x12\x005`$\xddk5\xd8\x7f!b=M<\xc6aP\x03`F'
|
||||
raw_blank = b''
|
||||
|
||||
test_data = b'hello'
|
||||
stream = MagicMock()
|
||||
#stream.read.return_value = add_header(test_data)
|
||||
stream.read.side_effect = [ raw_1_my_info, raw_2_node_info, raw_3_node_info, raw_4_complete,
|
||||
raw_5_prefs, raw_6_channel0, raw_7_channel1, raw_8_channel2,
|
||||
raw_blank, raw_blank]
|
||||
toRadio = MagicMock()
|
||||
toRadio.SerializeToString.return_value = test_data
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
iface = StreamInterface(noProto=True, connectNow=False)
|
||||
iface.stream = stream
|
||||
iface.connect()
|
||||
iface._sendToRadioImpl(toRadio)
|
||||
assert re.search(r'Sending: ', caplog.text, re.MULTILINE)
|
||||
assert re.search(r'reading character', caplog.text, re.MULTILINE)
|
||||
assert re.search(r'In reader loop', caplog.text, re.MULTILINE)
|
||||
print(caplog.text)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_stream_interface.test_StreamInterface" href="#meshtastic.tests.test_stream_interface.test_StreamInterface">test_StreamInterface</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_stream_interface.test_StreamInterface_with_noProto" href="#meshtastic.tests.test_stream_interface.test_StreamInterface_with_noProto">test_StreamInterface_with_noProto</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_stream_interface.test_sendToRadioImpl" href="#meshtastic.tests.test_stream_interface.test_sendToRadioImpl">test_sendToRadioImpl</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
120
docs/meshtastic/tests/test_tcp_interface.html
Normal file
120
docs/meshtastic/tests/test_tcp_interface.html
Normal file
@@ -0,0 +1,120 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_tcp_interface API documentation</title>
|
||||
<meta name="description" content="Meshtastic unit tests for tcp_interface.py" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_tcp_interface</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic unit tests for tcp_interface.py</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic unit tests for tcp_interface.py"""
|
||||
|
||||
import re
|
||||
|
||||
from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from ..tcp_interface import TCPInterface
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_TCPInterface(capsys):
|
||||
"""Test that we can instantiate a TCPInterface"""
|
||||
with patch('socket.socket') as mock_socket:
|
||||
iface = TCPInterface(hostname='localhost', noProto=True)
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Owner: None \(None\)', out, re.MULTILINE)
|
||||
assert re.search(r'Nodes', out, re.MULTILINE)
|
||||
assert re.search(r'Preferences', out, re.MULTILINE)
|
||||
assert re.search(r'Channels', out, re.MULTILINE)
|
||||
assert re.search(r'Primary channel URL', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
assert mock_socket.called
|
||||
iface.close()</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_tcp_interface.test_TCPInterface"><code class="name flex">
|
||||
<span>def <span class="ident">test_TCPInterface</span></span>(<span>capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test that we can instantiate a TCPInterface</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_TCPInterface(capsys):
|
||||
"""Test that we can instantiate a TCPInterface"""
|
||||
with patch('socket.socket') as mock_socket:
|
||||
iface = TCPInterface(hostname='localhost', noProto=True)
|
||||
iface.showInfo()
|
||||
iface.localNode.showInfo()
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'Owner: None \(None\)', out, re.MULTILINE)
|
||||
assert re.search(r'Nodes', out, re.MULTILINE)
|
||||
assert re.search(r'Preferences', out, re.MULTILINE)
|
||||
assert re.search(r'Channels', out, re.MULTILINE)
|
||||
assert re.search(r'Primary channel URL', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
assert mock_socket.called
|
||||
iface.close()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_tcp_interface.test_TCPInterface" href="#meshtastic.tests.test_tcp_interface.test_TCPInterface">test_TCPInterface</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
519
docs/meshtastic/tests/test_util.html
Normal file
519
docs/meshtastic/tests/test_util.html
Normal file
@@ -0,0 +1,519 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tests.test_util API documentation</title>
|
||||
<meta name="description" content="Meshtastic unit tests for util.py" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tests.test_util</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Meshtastic unit tests for util.py</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Meshtastic unit tests for util.py"""
|
||||
|
||||
import re
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
from meshtastic.util import (fixme, stripnl, pskToString, our_exit,
|
||||
support_info, genPSK256, fromStr, fromPSK,
|
||||
quoteBooleans, catchAndIgnore)
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_genPSK256():
|
||||
"""Test genPSK256"""
|
||||
assert genPSK256() != ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_fromStr():
|
||||
"""Test fromStr"""
|
||||
assert fromStr('') == b''
|
||||
assert fromStr('0x12') == b'\x12'
|
||||
assert fromStr('t')
|
||||
assert fromStr('T')
|
||||
assert fromStr('true')
|
||||
assert fromStr('True')
|
||||
assert fromStr('yes')
|
||||
assert fromStr('Yes')
|
||||
assert fromStr('f') is False
|
||||
assert fromStr('F') is False
|
||||
assert fromStr('false') is False
|
||||
assert fromStr('False') is False
|
||||
assert fromStr('no') is False
|
||||
assert fromStr('No') is False
|
||||
assert fromStr('100.01') == 100.01
|
||||
assert fromStr('123') == 123
|
||||
assert fromStr('abc') == 'abc'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_quoteBooleans():
|
||||
"""Test quoteBooleans"""
|
||||
assert quoteBooleans('') == ''
|
||||
assert quoteBooleans('foo') == 'foo'
|
||||
assert quoteBooleans('true') == 'true'
|
||||
assert quoteBooleans('false') == 'false'
|
||||
assert quoteBooleans(': true') == ": 'true'"
|
||||
assert quoteBooleans(': false') == ": 'false'"
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_fromPSK():
|
||||
"""Test fromPSK"""
|
||||
assert fromPSK('random') != ''
|
||||
assert fromPSK('none') == b'\x00'
|
||||
assert fromPSK('default') == b'\x01'
|
||||
assert fromPSK('simple22') == b'\x17'
|
||||
assert fromPSK('trash') == 'trash'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_stripnl():
|
||||
"""Test stripnl"""
|
||||
assert stripnl('') == ''
|
||||
assert stripnl('a\n') == 'a'
|
||||
assert stripnl(' a \n ') == 'a'
|
||||
assert stripnl('a\nb') == 'a b'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_empty_string():
|
||||
"""Test pskToString empty string"""
|
||||
assert pskToString('') == 'unencrypted'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_string():
|
||||
"""Test pskToString string"""
|
||||
assert pskToString('hunter123') == 'secret'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_one_byte_zero_value():
|
||||
"""Test pskToString one byte that is value of 0"""
|
||||
assert pskToString(bytes([0x00])) == 'unencrypted'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_one_byte_non_zero_value():
|
||||
"""Test pskToString one byte that is non-zero"""
|
||||
assert pskToString(bytes([0x01])) == 'default'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_many_bytes():
|
||||
"""Test pskToString many bytes"""
|
||||
assert pskToString(bytes([0x02, 0x01])) == 'secret'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_pskToString_simple():
|
||||
"""Test pskToString simple"""
|
||||
assert pskToString(bytes([0x03])) == 'simple2'
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_our_exit_zero_return_value():
|
||||
"""Test our_exit with a zero return value"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
our_exit("Warning: Some message", 0)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 0
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_our_exit_non_zero_return_value():
|
||||
"""Test our_exit with a non-zero return value"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
our_exit("Error: Some message", 1)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_fixme():
|
||||
"""Test fixme()"""
|
||||
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||
fixme("some exception")
|
||||
assert pytest_wrapped_e.type == Exception
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_support_info(capsys):
|
||||
"""Test support_info"""
|
||||
support_info()
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'System', out, re.MULTILINE)
|
||||
assert re.search(r'Platform', out, re.MULTILINE)
|
||||
assert re.search(r'Machine', out, re.MULTILINE)
|
||||
assert re.search(r'Executable', out, re.MULTILINE)
|
||||
assert err == ''
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_catchAndIgnore(caplog):
|
||||
"""Test catchAndIgnore() does not actually throw an exception, but just logs"""
|
||||
def some_closure():
|
||||
raise Exception('foo')
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
catchAndIgnore("something", some_closure)
|
||||
assert re.search(r'Exception thrown in something', caplog.text, re.MULTILINE)</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tests.test_util.test_catchAndIgnore"><code class="name flex">
|
||||
<span>def <span class="ident">test_catchAndIgnore</span></span>(<span>caplog)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test catchAndIgnore() does not actually throw an exception, but just logs</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_catchAndIgnore(caplog):
|
||||
"""Test catchAndIgnore() does not actually throw an exception, but just logs"""
|
||||
def some_closure():
|
||||
raise Exception('foo')
|
||||
with caplog.at_level(logging.DEBUG):
|
||||
catchAndIgnore("something", some_closure)
|
||||
assert re.search(r'Exception thrown in something', caplog.text, re.MULTILINE)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_fixme"><code class="name flex">
|
||||
<span>def <span class="ident">test_fixme</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test fixme()</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_fixme():
|
||||
"""Test fixme()"""
|
||||
with pytest.raises(Exception) as pytest_wrapped_e:
|
||||
fixme("some exception")
|
||||
assert pytest_wrapped_e.type == Exception</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_fromPSK"><code class="name flex">
|
||||
<span>def <span class="ident">test_fromPSK</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test fromPSK</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_fromPSK():
|
||||
"""Test fromPSK"""
|
||||
assert fromPSK('random') != ''
|
||||
assert fromPSK('none') == b'\x00'
|
||||
assert fromPSK('default') == b'\x01'
|
||||
assert fromPSK('simple22') == b'\x17'
|
||||
assert fromPSK('trash') == 'trash'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_fromStr"><code class="name flex">
|
||||
<span>def <span class="ident">test_fromStr</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test fromStr</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_fromStr():
|
||||
"""Test fromStr"""
|
||||
assert fromStr('') == b''
|
||||
assert fromStr('0x12') == b'\x12'
|
||||
assert fromStr('t')
|
||||
assert fromStr('T')
|
||||
assert fromStr('true')
|
||||
assert fromStr('True')
|
||||
assert fromStr('yes')
|
||||
assert fromStr('Yes')
|
||||
assert fromStr('f') is False
|
||||
assert fromStr('F') is False
|
||||
assert fromStr('false') is False
|
||||
assert fromStr('False') is False
|
||||
assert fromStr('no') is False
|
||||
assert fromStr('No') is False
|
||||
assert fromStr('100.01') == 100.01
|
||||
assert fromStr('123') == 123
|
||||
assert fromStr('abc') == 'abc'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_genPSK256"><code class="name flex">
|
||||
<span>def <span class="ident">test_genPSK256</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test genPSK256</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_genPSK256():
|
||||
"""Test genPSK256"""
|
||||
assert genPSK256() != ''</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_our_exit_non_zero_return_value"><code class="name flex">
|
||||
<span>def <span class="ident">test_our_exit_non_zero_return_value</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test our_exit with a non-zero return value</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_our_exit_non_zero_return_value():
|
||||
"""Test our_exit with a non-zero return value"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
our_exit("Error: Some message", 1)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 1</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_our_exit_zero_return_value"><code class="name flex">
|
||||
<span>def <span class="ident">test_our_exit_zero_return_value</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test our_exit with a zero return value</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_our_exit_zero_return_value():
|
||||
"""Test our_exit with a zero return value"""
|
||||
with pytest.raises(SystemExit) as pytest_wrapped_e:
|
||||
our_exit("Warning: Some message", 0)
|
||||
assert pytest_wrapped_e.type == SystemExit
|
||||
assert pytest_wrapped_e.value.code == 0</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_pskToString_empty_string"><code class="name flex">
|
||||
<span>def <span class="ident">test_pskToString_empty_string</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test pskToString empty string</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_pskToString_empty_string():
|
||||
"""Test pskToString empty string"""
|
||||
assert pskToString('') == 'unencrypted'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_pskToString_many_bytes"><code class="name flex">
|
||||
<span>def <span class="ident">test_pskToString_many_bytes</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test pskToString many bytes</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_pskToString_many_bytes():
|
||||
"""Test pskToString many bytes"""
|
||||
assert pskToString(bytes([0x02, 0x01])) == 'secret'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_pskToString_one_byte_non_zero_value"><code class="name flex">
|
||||
<span>def <span class="ident">test_pskToString_one_byte_non_zero_value</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test pskToString one byte that is non-zero</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_pskToString_one_byte_non_zero_value():
|
||||
"""Test pskToString one byte that is non-zero"""
|
||||
assert pskToString(bytes([0x01])) == 'default'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_pskToString_one_byte_zero_value"><code class="name flex">
|
||||
<span>def <span class="ident">test_pskToString_one_byte_zero_value</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test pskToString one byte that is value of 0</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_pskToString_one_byte_zero_value():
|
||||
"""Test pskToString one byte that is value of 0"""
|
||||
assert pskToString(bytes([0x00])) == 'unencrypted'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_pskToString_simple"><code class="name flex">
|
||||
<span>def <span class="ident">test_pskToString_simple</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test pskToString simple</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_pskToString_simple():
|
||||
"""Test pskToString simple"""
|
||||
assert pskToString(bytes([0x03])) == 'simple2'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_pskToString_string"><code class="name flex">
|
||||
<span>def <span class="ident">test_pskToString_string</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test pskToString string</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_pskToString_string():
|
||||
"""Test pskToString string"""
|
||||
assert pskToString('hunter123') == 'secret'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_quoteBooleans"><code class="name flex">
|
||||
<span>def <span class="ident">test_quoteBooleans</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test quoteBooleans</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_quoteBooleans():
|
||||
"""Test quoteBooleans"""
|
||||
assert quoteBooleans('') == ''
|
||||
assert quoteBooleans('foo') == 'foo'
|
||||
assert quoteBooleans('true') == 'true'
|
||||
assert quoteBooleans('false') == 'false'
|
||||
assert quoteBooleans(': true') == ": 'true'"
|
||||
assert quoteBooleans(': false') == ": 'false'"</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_stripnl"><code class="name flex">
|
||||
<span>def <span class="ident">test_stripnl</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test stripnl</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_stripnl():
|
||||
"""Test stripnl"""
|
||||
assert stripnl('') == ''
|
||||
assert stripnl('a\n') == 'a'
|
||||
assert stripnl(' a \n ') == 'a'
|
||||
assert stripnl('a\nb') == 'a b'</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tests.test_util.test_support_info"><code class="name flex">
|
||||
<span>def <span class="ident">test_support_info</span></span>(<span>capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Test support_info</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.mark.unit
|
||||
def test_support_info(capsys):
|
||||
"""Test support_info"""
|
||||
support_info()
|
||||
out, err = capsys.readouterr()
|
||||
assert re.search(r'System', out, re.MULTILINE)
|
||||
assert re.search(r'Platform', out, re.MULTILINE)
|
||||
assert re.search(r'Machine', out, re.MULTILINE)
|
||||
assert re.search(r'Executable', out, re.MULTILINE)
|
||||
assert err == ''</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic.tests" href="index.html">meshtastic.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tests.test_util.test_catchAndIgnore" href="#meshtastic.tests.test_util.test_catchAndIgnore">test_catchAndIgnore</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_fixme" href="#meshtastic.tests.test_util.test_fixme">test_fixme</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_fromPSK" href="#meshtastic.tests.test_util.test_fromPSK">test_fromPSK</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_fromStr" href="#meshtastic.tests.test_util.test_fromStr">test_fromStr</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_genPSK256" href="#meshtastic.tests.test_util.test_genPSK256">test_genPSK256</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_our_exit_non_zero_return_value" href="#meshtastic.tests.test_util.test_our_exit_non_zero_return_value">test_our_exit_non_zero_return_value</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_our_exit_zero_return_value" href="#meshtastic.tests.test_util.test_our_exit_zero_return_value">test_our_exit_zero_return_value</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_pskToString_empty_string" href="#meshtastic.tests.test_util.test_pskToString_empty_string">test_pskToString_empty_string</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_pskToString_many_bytes" href="#meshtastic.tests.test_util.test_pskToString_many_bytes">test_pskToString_many_bytes</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_pskToString_one_byte_non_zero_value" href="#meshtastic.tests.test_util.test_pskToString_one_byte_non_zero_value">test_pskToString_one_byte_non_zero_value</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_pskToString_one_byte_zero_value" href="#meshtastic.tests.test_util.test_pskToString_one_byte_zero_value">test_pskToString_one_byte_zero_value</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_pskToString_simple" href="#meshtastic.tests.test_util.test_pskToString_simple">test_pskToString_simple</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_pskToString_string" href="#meshtastic.tests.test_util.test_pskToString_string">test_pskToString_string</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_quoteBooleans" href="#meshtastic.tests.test_util.test_quoteBooleans">test_quoteBooleans</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_stripnl" href="#meshtastic.tests.test_util.test_stripnl">test_stripnl</a></code></li>
|
||||
<li><code><a title="meshtastic.tests.test_util.test_support_info" href="#meshtastic.tests.test_util.test_support_info">test_support_info</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
615
docs/meshtastic/tunnel.html
Normal file
615
docs/meshtastic/tunnel.html
Normal file
@@ -0,0 +1,615 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.tunnel API documentation</title>
|
||||
<meta name="description" content="Code for IP tunnel over a mesh …" />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.tunnel</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Code for IP tunnel over a mesh</p>
|
||||
<h1 id="note-python-pytuntap-was-too-buggy">Note python-pytuntap was too buggy</h1>
|
||||
<h1 id="using-pip3-install-pytap2">using pip3 install pytap2</h1>
|
||||
<h1 id="make-sure-to-sudo-setcap-cap_net_admineip-usrbinpython38-so-python-can-access-tun-device-without-being-root">make sure to "sudo setcap cap_net_admin+eip /usr/bin/python3.8" so python can access tun device without being root</h1>
|
||||
<h1 id="sudo-ip-tuntap-del-mode-tun-tun0">sudo ip tuntap del mode tun tun0</h1>
|
||||
<h1 id="sudo-binrunsh-port-devttyusb0-setch-shortfast">sudo bin/run.sh –port /dev/ttyUSB0 –setch-shortfast</h1>
|
||||
<h1 id="sudo-binrunsh-port-devttyusb0-tunnel-debug">sudo bin/run.sh –port /dev/ttyUSB0 –tunnel –debug</h1>
|
||||
<h1 id="ssh-y-root19216810151-or-dietpi-default-password-p">ssh -Y root@192.168.10.151 (or dietpi), default password p</h1>
|
||||
<h1 id="ncat-e-bincat-k-u-l-1235">ncat -e /bin/cat -k -u -l 1235</h1>
|
||||
<h1 id="ncat-u-1011564152-1235">ncat -u 10.115.64.152 1235</h1>
|
||||
<h1 id="ping-c-1-w-20-1011564152">ping -c 1 -W 20 10.115.64.152</h1>
|
||||
<h1 id="ping-i-30-w-30-1011564152">ping -i 30 -W 30 10.115.64.152</h1>
|
||||
<h1 id="fixme-use-a-more-optimal-mtu">FIXME: use a more optimal MTU</h1>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Code for IP tunnel over a mesh
|
||||
|
||||
# Note python-pytuntap was too buggy
|
||||
# using pip3 install pytap2
|
||||
# make sure to "sudo setcap cap_net_admin+eip /usr/bin/python3.8" so python can access tun device without being root
|
||||
# sudo ip tuntap del mode tun tun0
|
||||
# sudo bin/run.sh --port /dev/ttyUSB0 --setch-shortfast
|
||||
# sudo bin/run.sh --port /dev/ttyUSB0 --tunnel --debug
|
||||
# ssh -Y root@192.168.10.151 (or dietpi), default password p
|
||||
# ncat -e /bin/cat -k -u -l 1235
|
||||
# ncat -u 10.115.64.152 1235
|
||||
# ping -c 1 -W 20 10.115.64.152
|
||||
# ping -i 30 -W 30 10.115.64.152
|
||||
|
||||
# FIXME: use a more optimal MTU
|
||||
"""
|
||||
|
||||
import logging
|
||||
import threading
|
||||
from pubsub import pub
|
||||
|
||||
from pytap2 import TapDevice
|
||||
|
||||
from . import portnums_pb2
|
||||
|
||||
# A new non standard log level that is lower level than DEBUG
|
||||
LOG_TRACE = 5
|
||||
|
||||
# fixme - find a way to move onTunnelReceive inside of the class
|
||||
tunnelInstance = None
|
||||
|
||||
"""A list of chatty UDP services we should never accidentally
|
||||
forward to our slow network"""
|
||||
udpBlacklist = {
|
||||
1900, # SSDP
|
||||
5353, # multicast DNS
|
||||
}
|
||||
|
||||
"""A list of TCP services to block"""
|
||||
tcpBlacklist = {}
|
||||
|
||||
"""A list of protocols we ignore"""
|
||||
protocolBlacklist = {
|
||||
0x02, # IGMP
|
||||
0x80, # Service-Specific Connection-Oriented Protocol in a Multilink and Connectionless Environment
|
||||
}
|
||||
|
||||
|
||||
def hexstr(barray):
|
||||
"""Print a string of hex digits"""
|
||||
return ":".join('{:02x}'.format(x) for x in barray)
|
||||
|
||||
|
||||
def ipstr(barray):
|
||||
"""Print a string of ip digits"""
|
||||
return ".".join('{}'.format(x) for x in barray)
|
||||
|
||||
|
||||
def readnet_u16(p, offset):
|
||||
"""Read big endian u16 (network byte order)"""
|
||||
return p[offset] * 256 + p[offset + 1]
|
||||
|
||||
|
||||
def onTunnelReceive(packet, interface):
|
||||
"""Callback for received tunneled messages from mesh
|
||||
|
||||
FIXME figure out how to do closures with methods in python"""
|
||||
tunnelInstance.onReceive(packet)
|
||||
|
||||
|
||||
class Tunnel:
|
||||
"""A TUN based IP tunnel over meshtastic"""
|
||||
|
||||
def __init__(self, iface, subnet=None, netmask="255.255.0.0"):
|
||||
"""
|
||||
Constructor
|
||||
|
||||
iface is the already open MeshInterface instance
|
||||
subnet is used to construct our network number (normally 10.115.x.x)
|
||||
"""
|
||||
|
||||
if subnet is None:
|
||||
subnet = "10.115"
|
||||
|
||||
self.iface = iface
|
||||
self.subnetPrefix = subnet
|
||||
|
||||
global tunnelInstance
|
||||
tunnelInstance = self
|
||||
|
||||
logging.info("Starting IP to mesh tunnel (you must be root for this *pre-alpha* "\
|
||||
"feature to work). Mesh members:")
|
||||
|
||||
pub.subscribe(onTunnelReceive, "meshtastic.receive.data.IP_TUNNEL_APP")
|
||||
myAddr = self._nodeNumToIp(self.iface.myInfo.my_node_num)
|
||||
|
||||
for node in self.iface.nodes.values():
|
||||
nodeId = node["user"]["id"]
|
||||
ip = self._nodeNumToIp(node["num"])
|
||||
logging.info(f"Node { nodeId } has IP address { ip }")
|
||||
|
||||
logging.debug("creating TUN device with MTU=200")
|
||||
# FIXME - figure out real max MTU, it should be 240 - the overhead bytes for SubPacket and Data
|
||||
self.tun = TapDevice(name="mesh")
|
||||
self.tun.up()
|
||||
self.tun.ifconfig(address=myAddr, netmask=netmask, mtu=200)
|
||||
logging.debug(f"starting TUN reader, our IP address is {myAddr}")
|
||||
self._rxThread = threading.Thread(
|
||||
target=self.__tunReader, args=(), daemon=True)
|
||||
self._rxThread.start()
|
||||
|
||||
def onReceive(self, packet):
|
||||
"""onReceive"""
|
||||
p = packet["decoded"]["payload"]
|
||||
if packet["from"] == self.iface.myInfo.my_node_num:
|
||||
logging.debug("Ignoring message we sent")
|
||||
else:
|
||||
logging.debug(
|
||||
f"Received mesh tunnel message type={type(p)} len={len(p)}")
|
||||
# we don't really need to check for filtering here (sender should have checked),
|
||||
# but this provides useful debug printing on types of packets received
|
||||
if not self._shouldFilterPacket(p):
|
||||
self.tun.write(p)
|
||||
|
||||
def _shouldFilterPacket(self, p):
|
||||
"""Given a packet, decode it and return true if it should be ignored"""
|
||||
protocol = p[8 + 1]
|
||||
srcaddr = p[12:16]
|
||||
destAddr = p[16:20]
|
||||
subheader = 20
|
||||
ignore = False # Assume we will be forwarding the packet
|
||||
if protocol in protocolBlacklist:
|
||||
ignore = True
|
||||
logging.log(
|
||||
LOG_TRACE, f"Ignoring blacklisted protocol 0x{protocol:02x}")
|
||||
elif protocol == 0x01: # ICMP
|
||||
icmpType = p[20]
|
||||
icmpCode = p[21]
|
||||
checksum = p[22:24]
|
||||
# pylint: disable=line-too-long
|
||||
logging.debug(f"forwarding ICMP message src={ipstr(srcaddr)}, dest={ipstr(destAddr)}, type={icmpType}, code={icmpCode}, checksum={checksum}")
|
||||
# reply to pings (swap src and dest but keep rest of packet unchanged)
|
||||
#pingback = p[:12]+p[16:20]+p[12:16]+p[20:]
|
||||
# tap.write(pingback)
|
||||
elif protocol == 0x11: # UDP
|
||||
srcport = readnet_u16(p, subheader)
|
||||
destport = readnet_u16(p, subheader + 2)
|
||||
if destport in udpBlacklist:
|
||||
ignore = True
|
||||
logging.log(
|
||||
LOG_TRACE, f"ignoring blacklisted UDP port {destport}")
|
||||
else:
|
||||
logging.debug(
|
||||
f"forwarding udp srcport={srcport}, destport={destport}")
|
||||
elif protocol == 0x06: # TCP
|
||||
srcport = readnet_u16(p, subheader)
|
||||
destport = readnet_u16(p, subheader + 2)
|
||||
if destport in tcpBlacklist:
|
||||
ignore = True
|
||||
logging.log(LOG_TRACE, f"ignoring blacklisted TCP port {destport}")
|
||||
else:
|
||||
logging.debug(f"forwarding tcp srcport={srcport}, destport={destport}")
|
||||
else:
|
||||
logging.warning(f"forwarding unexpected protocol 0x{protocol:02x}, "\
|
||||
"src={ipstr(srcaddr)}, dest={ipstr(destAddr)}")
|
||||
|
||||
return ignore
|
||||
|
||||
def __tunReader(self):
|
||||
tap = self.tun
|
||||
logging.debug("TUN reader running")
|
||||
while True:
|
||||
p = tap.read()
|
||||
#logging.debug(f"IP packet received on TUN interface, type={type(p)}")
|
||||
destAddr = p[16:20]
|
||||
|
||||
if not self._shouldFilterPacket(p):
|
||||
self.sendPacket(destAddr, p)
|
||||
|
||||
def _ipToNodeId(self, ipAddr):
|
||||
# We only consider the last 16 bits of the nodenum for IP address matching
|
||||
ipBits = ipAddr[2] * 256 + ipAddr[3]
|
||||
|
||||
if ipBits == 0xffff:
|
||||
return "^all"
|
||||
|
||||
for node in self.iface.nodes.values():
|
||||
nodeNum = node["num"] & 0xffff
|
||||
# logging.debug(f"Considering nodenum 0x{nodeNum:x} for ipBits 0x{ipBits:x}")
|
||||
if (nodeNum) == ipBits:
|
||||
return node["user"]["id"]
|
||||
return None
|
||||
|
||||
def _nodeNumToIp(self, nodeNum):
|
||||
return f"{self.subnetPrefix}.{(nodeNum >> 8) & 0xff}.{nodeNum & 0xff}"
|
||||
|
||||
def sendPacket(self, destAddr, p):
|
||||
"""Forward the provided IP packet into the mesh"""
|
||||
nodeId = self._ipToNodeId(destAddr)
|
||||
if nodeId is not None:
|
||||
logging.debug(f"Forwarding packet bytelen={len(p)} dest={ipstr(destAddr)}, destNode={nodeId}")
|
||||
self.iface.sendData(
|
||||
p, nodeId, portnums_pb2.IP_TUNNEL_APP, wantAck=False)
|
||||
else:
|
||||
logging.warning(f"Dropping packet because no node found for destIP={ipstr(destAddr)}")
|
||||
|
||||
def close(self):
|
||||
"""Close"""
|
||||
self.tun.close()</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-variables">Global variables</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tunnel.tcpBlacklist"><code class="name">var <span class="ident">tcpBlacklist</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A list of protocols we ignore</p></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.tunnel.tunnelInstance"><code class="name">var <span class="ident">tunnelInstance</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A list of chatty UDP services we should never accidentally
|
||||
forward to our slow network</p></div>
|
||||
</dd>
|
||||
<dt id="meshtastic.tunnel.udpBlacklist"><code class="name">var <span class="ident">udpBlacklist</span></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A list of TCP services to block</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tunnel.hexstr"><code class="name flex">
|
||||
<span>def <span class="ident">hexstr</span></span>(<span>barray)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Print a string of hex digits</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def hexstr(barray):
|
||||
"""Print a string of hex digits"""
|
||||
return ":".join('{:02x}'.format(x) for x in barray)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tunnel.ipstr"><code class="name flex">
|
||||
<span>def <span class="ident">ipstr</span></span>(<span>barray)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Print a string of ip digits</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def ipstr(barray):
|
||||
"""Print a string of ip digits"""
|
||||
return ".".join('{}'.format(x) for x in barray)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tunnel.onTunnelReceive"><code class="name flex">
|
||||
<span>def <span class="ident">onTunnelReceive</span></span>(<span>packet, interface)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Callback for received tunneled messages from mesh</p>
|
||||
<p>FIXME figure out how to do closures with methods in python</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def onTunnelReceive(packet, interface):
|
||||
"""Callback for received tunneled messages from mesh
|
||||
|
||||
FIXME figure out how to do closures with methods in python"""
|
||||
tunnelInstance.onReceive(packet)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tunnel.readnet_u16"><code class="name flex">
|
||||
<span>def <span class="ident">readnet_u16</span></span>(<span>p, offset)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Read big endian u16 (network byte order)</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def readnet_u16(p, offset):
|
||||
"""Read big endian u16 (network byte order)"""
|
||||
return p[offset] * 256 + p[offset + 1]</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.tunnel.Tunnel"><code class="flex name class">
|
||||
<span>class <span class="ident">Tunnel</span></span>
|
||||
<span>(</span><span>iface, subnet=None, netmask='255.255.0.0')</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A TUN based IP tunnel over meshtastic</p>
|
||||
<p>Constructor</p>
|
||||
<p>iface is the already open MeshInterface instance
|
||||
subnet is used to construct our network number (normally 10.115.x.x)</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class Tunnel:
|
||||
"""A TUN based IP tunnel over meshtastic"""
|
||||
|
||||
def __init__(self, iface, subnet=None, netmask="255.255.0.0"):
|
||||
"""
|
||||
Constructor
|
||||
|
||||
iface is the already open MeshInterface instance
|
||||
subnet is used to construct our network number (normally 10.115.x.x)
|
||||
"""
|
||||
|
||||
if subnet is None:
|
||||
subnet = "10.115"
|
||||
|
||||
self.iface = iface
|
||||
self.subnetPrefix = subnet
|
||||
|
||||
global tunnelInstance
|
||||
tunnelInstance = self
|
||||
|
||||
logging.info("Starting IP to mesh tunnel (you must be root for this *pre-alpha* "\
|
||||
"feature to work). Mesh members:")
|
||||
|
||||
pub.subscribe(onTunnelReceive, "meshtastic.receive.data.IP_TUNNEL_APP")
|
||||
myAddr = self._nodeNumToIp(self.iface.myInfo.my_node_num)
|
||||
|
||||
for node in self.iface.nodes.values():
|
||||
nodeId = node["user"]["id"]
|
||||
ip = self._nodeNumToIp(node["num"])
|
||||
logging.info(f"Node { nodeId } has IP address { ip }")
|
||||
|
||||
logging.debug("creating TUN device with MTU=200")
|
||||
# FIXME - figure out real max MTU, it should be 240 - the overhead bytes for SubPacket and Data
|
||||
self.tun = TapDevice(name="mesh")
|
||||
self.tun.up()
|
||||
self.tun.ifconfig(address=myAddr, netmask=netmask, mtu=200)
|
||||
logging.debug(f"starting TUN reader, our IP address is {myAddr}")
|
||||
self._rxThread = threading.Thread(
|
||||
target=self.__tunReader, args=(), daemon=True)
|
||||
self._rxThread.start()
|
||||
|
||||
def onReceive(self, packet):
|
||||
"""onReceive"""
|
||||
p = packet["decoded"]["payload"]
|
||||
if packet["from"] == self.iface.myInfo.my_node_num:
|
||||
logging.debug("Ignoring message we sent")
|
||||
else:
|
||||
logging.debug(
|
||||
f"Received mesh tunnel message type={type(p)} len={len(p)}")
|
||||
# we don't really need to check for filtering here (sender should have checked),
|
||||
# but this provides useful debug printing on types of packets received
|
||||
if not self._shouldFilterPacket(p):
|
||||
self.tun.write(p)
|
||||
|
||||
def _shouldFilterPacket(self, p):
|
||||
"""Given a packet, decode it and return true if it should be ignored"""
|
||||
protocol = p[8 + 1]
|
||||
srcaddr = p[12:16]
|
||||
destAddr = p[16:20]
|
||||
subheader = 20
|
||||
ignore = False # Assume we will be forwarding the packet
|
||||
if protocol in protocolBlacklist:
|
||||
ignore = True
|
||||
logging.log(
|
||||
LOG_TRACE, f"Ignoring blacklisted protocol 0x{protocol:02x}")
|
||||
elif protocol == 0x01: # ICMP
|
||||
icmpType = p[20]
|
||||
icmpCode = p[21]
|
||||
checksum = p[22:24]
|
||||
# pylint: disable=line-too-long
|
||||
logging.debug(f"forwarding ICMP message src={ipstr(srcaddr)}, dest={ipstr(destAddr)}, type={icmpType}, code={icmpCode}, checksum={checksum}")
|
||||
# reply to pings (swap src and dest but keep rest of packet unchanged)
|
||||
#pingback = p[:12]+p[16:20]+p[12:16]+p[20:]
|
||||
# tap.write(pingback)
|
||||
elif protocol == 0x11: # UDP
|
||||
srcport = readnet_u16(p, subheader)
|
||||
destport = readnet_u16(p, subheader + 2)
|
||||
if destport in udpBlacklist:
|
||||
ignore = True
|
||||
logging.log(
|
||||
LOG_TRACE, f"ignoring blacklisted UDP port {destport}")
|
||||
else:
|
||||
logging.debug(
|
||||
f"forwarding udp srcport={srcport}, destport={destport}")
|
||||
elif protocol == 0x06: # TCP
|
||||
srcport = readnet_u16(p, subheader)
|
||||
destport = readnet_u16(p, subheader + 2)
|
||||
if destport in tcpBlacklist:
|
||||
ignore = True
|
||||
logging.log(LOG_TRACE, f"ignoring blacklisted TCP port {destport}")
|
||||
else:
|
||||
logging.debug(f"forwarding tcp srcport={srcport}, destport={destport}")
|
||||
else:
|
||||
logging.warning(f"forwarding unexpected protocol 0x{protocol:02x}, "\
|
||||
"src={ipstr(srcaddr)}, dest={ipstr(destAddr)}")
|
||||
|
||||
return ignore
|
||||
|
||||
def __tunReader(self):
|
||||
tap = self.tun
|
||||
logging.debug("TUN reader running")
|
||||
while True:
|
||||
p = tap.read()
|
||||
#logging.debug(f"IP packet received on TUN interface, type={type(p)}")
|
||||
destAddr = p[16:20]
|
||||
|
||||
if not self._shouldFilterPacket(p):
|
||||
self.sendPacket(destAddr, p)
|
||||
|
||||
def _ipToNodeId(self, ipAddr):
|
||||
# We only consider the last 16 bits of the nodenum for IP address matching
|
||||
ipBits = ipAddr[2] * 256 + ipAddr[3]
|
||||
|
||||
if ipBits == 0xffff:
|
||||
return "^all"
|
||||
|
||||
for node in self.iface.nodes.values():
|
||||
nodeNum = node["num"] & 0xffff
|
||||
# logging.debug(f"Considering nodenum 0x{nodeNum:x} for ipBits 0x{ipBits:x}")
|
||||
if (nodeNum) == ipBits:
|
||||
return node["user"]["id"]
|
||||
return None
|
||||
|
||||
def _nodeNumToIp(self, nodeNum):
|
||||
return f"{self.subnetPrefix}.{(nodeNum >> 8) & 0xff}.{nodeNum & 0xff}"
|
||||
|
||||
def sendPacket(self, destAddr, p):
|
||||
"""Forward the provided IP packet into the mesh"""
|
||||
nodeId = self._ipToNodeId(destAddr)
|
||||
if nodeId is not None:
|
||||
logging.debug(f"Forwarding packet bytelen={len(p)} dest={ipstr(destAddr)}, destNode={nodeId}")
|
||||
self.iface.sendData(
|
||||
p, nodeId, portnums_pb2.IP_TUNNEL_APP, wantAck=False)
|
||||
else:
|
||||
logging.warning(f"Dropping packet because no node found for destIP={ipstr(destAddr)}")
|
||||
|
||||
def close(self):
|
||||
"""Close"""
|
||||
self.tun.close()</code></pre>
|
||||
</details>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.tunnel.Tunnel.close"><code class="name flex">
|
||||
<span>def <span class="ident">close</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Close</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def close(self):
|
||||
"""Close"""
|
||||
self.tun.close()</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tunnel.Tunnel.onReceive"><code class="name flex">
|
||||
<span>def <span class="ident">onReceive</span></span>(<span>self, packet)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>onReceive</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def onReceive(self, packet):
|
||||
"""onReceive"""
|
||||
p = packet["decoded"]["payload"]
|
||||
if packet["from"] == self.iface.myInfo.my_node_num:
|
||||
logging.debug("Ignoring message we sent")
|
||||
else:
|
||||
logging.debug(
|
||||
f"Received mesh tunnel message type={type(p)} len={len(p)}")
|
||||
# we don't really need to check for filtering here (sender should have checked),
|
||||
# but this provides useful debug printing on types of packets received
|
||||
if not self._shouldFilterPacket(p):
|
||||
self.tun.write(p)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.tunnel.Tunnel.sendPacket"><code class="name flex">
|
||||
<span>def <span class="ident">sendPacket</span></span>(<span>self, destAddr, p)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Forward the provided IP packet into the mesh</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def sendPacket(self, destAddr, p):
|
||||
"""Forward the provided IP packet into the mesh"""
|
||||
nodeId = self._ipToNodeId(destAddr)
|
||||
if nodeId is not None:
|
||||
logging.debug(f"Forwarding packet bytelen={len(p)} dest={ipstr(destAddr)}, destNode={nodeId}")
|
||||
self.iface.sendData(
|
||||
p, nodeId, portnums_pb2.IP_TUNNEL_APP, wantAck=False)
|
||||
else:
|
||||
logging.warning(f"Dropping packet because no node found for destIP={ipstr(destAddr)}")</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul>
|
||||
<li><a href="#note-python-pytuntap-was-too-buggy">Note python-pytuntap was too buggy</a></li>
|
||||
<li><a href="#using-pip3-install-pytap2">using pip3 install pytap2</a></li>
|
||||
<li><a href="#make-sure-to-sudo-setcap-cap_net_admineip-usrbinpython38-so-python-can-access-tun-device-without-being-root">make sure to "sudo setcap cap_net_admin+eip /usr/bin/python3.8" so python can access tun device without being root</a></li>
|
||||
<li><a href="#sudo-ip-tuntap-del-mode-tun-tun0">sudo ip tuntap del mode tun tun0</a></li>
|
||||
<li><a href="#sudo-binrunsh-port-devttyusb0-setch-shortfast">sudo bin/run.sh –port /dev/ttyUSB0 –setch-shortfast</a></li>
|
||||
<li><a href="#sudo-binrunsh-port-devttyusb0-tunnel-debug">sudo bin/run.sh –port /dev/ttyUSB0 –tunnel –debug</a></li>
|
||||
<li><a href="#ssh-y-root19216810151-or-dietpi-default-password-p">ssh -Y root@192.168.10.151 (or dietpi), default password p</a></li>
|
||||
<li><a href="#ncat-e-bincat-k-u-l-1235">ncat -e /bin/cat -k -u -l 1235</a></li>
|
||||
<li><a href="#ncat-u-1011564152-1235">ncat -u 10.115.64.152 1235</a></li>
|
||||
<li><a href="#ping-c-1-w-20-1011564152">ping -c 1 -W 20 10.115.64.152</a></li>
|
||||
<li><a href="#ping-i-30-w-30-1011564152">ping -i 30 -W 30 10.115.64.152</a></li>
|
||||
<li><a href="#fixme-use-a-more-optimal-mtu">FIXME: use a more optimal MTU</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-variables">Global variables</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tunnel.tcpBlacklist" href="#meshtastic.tunnel.tcpBlacklist">tcpBlacklist</a></code></li>
|
||||
<li><code><a title="meshtastic.tunnel.tunnelInstance" href="#meshtastic.tunnel.tunnelInstance">tunnelInstance</a></code></li>
|
||||
<li><code><a title="meshtastic.tunnel.udpBlacklist" href="#meshtastic.tunnel.udpBlacklist">udpBlacklist</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tunnel.hexstr" href="#meshtastic.tunnel.hexstr">hexstr</a></code></li>
|
||||
<li><code><a title="meshtastic.tunnel.ipstr" href="#meshtastic.tunnel.ipstr">ipstr</a></code></li>
|
||||
<li><code><a title="meshtastic.tunnel.onTunnelReceive" href="#meshtastic.tunnel.onTunnelReceive">onTunnelReceive</a></code></li>
|
||||
<li><code><a title="meshtastic.tunnel.readnet_u16" href="#meshtastic.tunnel.readnet_u16">readnet_u16</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.tunnel.Tunnel" href="#meshtastic.tunnel.Tunnel">Tunnel</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.tunnel.Tunnel.close" href="#meshtastic.tunnel.Tunnel.close">close</a></code></li>
|
||||
<li><code><a title="meshtastic.tunnel.Tunnel.onReceive" href="#meshtastic.tunnel.Tunnel.onReceive">onReceive</a></code></li>
|
||||
<li><code><a title="meshtastic.tunnel.Tunnel.sendPacket" href="#meshtastic.tunnel.Tunnel.sendPacket">sendPacket</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
688
docs/meshtastic/util.html
Normal file
688
docs/meshtastic/util.html
Normal file
@@ -0,0 +1,688 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
|
||||
<meta name="generator" content="pdoc 0.10.0" />
|
||||
<title>meshtastic.util API documentation</title>
|
||||
<meta name="description" content="Utility functions." />
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
|
||||
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
|
||||
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
|
||||
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
|
||||
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
|
||||
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
|
||||
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
|
||||
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<article id="content">
|
||||
<header>
|
||||
<h1 class="title">Module <code>meshtastic.util</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Utility functions.</p>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">"""Utility functions.
|
||||
"""
|
||||
import traceback
|
||||
from queue import Queue
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import platform
|
||||
import logging
|
||||
import threading
|
||||
import serial
|
||||
import serial.tools.list_ports
|
||||
import pkg_resources
|
||||
|
||||
"""Some devices such as a seger jlink we never want to accidentally open"""
|
||||
blacklistVids = dict.fromkeys([0x1366])
|
||||
|
||||
|
||||
def quoteBooleans(a_string):
|
||||
"""Quote booleans
|
||||
given a string that contains ": true", replace with ": 'true'" (or false)
|
||||
"""
|
||||
tmp = a_string.replace(": true", ": 'true'")
|
||||
tmp = tmp.replace(": false", ": 'false'")
|
||||
return tmp
|
||||
|
||||
def genPSK256():
|
||||
"""Generate a random preshared key"""
|
||||
return os.urandom(32)
|
||||
|
||||
|
||||
def fromPSK(valstr):
|
||||
"""A special version of fromStr that assumes the user is trying to set a PSK.
|
||||
In that case we also allow "none", "default" or "random" (to have python generate one), or simpleN
|
||||
"""
|
||||
if valstr == "random":
|
||||
return genPSK256()
|
||||
elif valstr == "none":
|
||||
return bytes([0]) # Use the 'no encryption' PSK
|
||||
elif valstr == "default":
|
||||
return bytes([1]) # Use default channel psk
|
||||
elif valstr.startswith("simple"):
|
||||
# Use one of the single byte encodings
|
||||
return bytes([int(valstr[6:]) + 1])
|
||||
else:
|
||||
return fromStr(valstr)
|
||||
|
||||
|
||||
def fromStr(valstr):
|
||||
"""Try to parse as int, float or bool (and fallback to a string as last resort)
|
||||
|
||||
Returns: an int, bool, float, str or byte array (for strings of hex digits)
|
||||
|
||||
Args:
|
||||
valstr (string): A user provided string
|
||||
"""
|
||||
if len(valstr) == 0: # Treat an emptystring as an empty bytes
|
||||
val = bytes()
|
||||
elif valstr.startswith('0x'):
|
||||
# if needed convert to string with asBytes.decode('utf-8')
|
||||
val = bytes.fromhex(valstr[2:])
|
||||
elif valstr.lower() in {"t", "true", "yes"}:
|
||||
val = True
|
||||
elif valstr.lower() in {"f", "false", "no"}:
|
||||
val = False
|
||||
else:
|
||||
try:
|
||||
val = int(valstr)
|
||||
except ValueError:
|
||||
try:
|
||||
val = float(valstr)
|
||||
except ValueError:
|
||||
val = valstr # Not a float or an int, assume string
|
||||
return val
|
||||
|
||||
|
||||
def pskToString(psk: bytes):
|
||||
"""Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string"""
|
||||
if len(psk) == 0:
|
||||
return "unencrypted"
|
||||
elif len(psk) == 1:
|
||||
b = psk[0]
|
||||
if b == 0:
|
||||
return "unencrypted"
|
||||
elif b == 1:
|
||||
return "default"
|
||||
else:
|
||||
return f"simple{b - 1}"
|
||||
else:
|
||||
return "secret"
|
||||
|
||||
|
||||
def stripnl(s):
|
||||
"""Remove newlines from a string (and remove extra whitespace)"""
|
||||
s = str(s).replace("\n", " ")
|
||||
return ' '.join(s.split())
|
||||
|
||||
|
||||
def fixme(message):
|
||||
"""Raise an exception for things that needs to be fixed"""
|
||||
raise Exception(f"FIXME: {message}")
|
||||
|
||||
|
||||
def catchAndIgnore(reason, closure):
|
||||
"""Call a closure but if it throws an exception print it and continue"""
|
||||
try:
|
||||
closure()
|
||||
except BaseException as ex:
|
||||
logging.error(f"Exception thrown in {reason}: {ex}")
|
||||
|
||||
|
||||
def findPorts():
|
||||
"""Find all ports that might have meshtastic devices
|
||||
|
||||
Returns:
|
||||
list -- a list of device paths
|
||||
"""
|
||||
l = list(map(lambda port: port.device,
|
||||
filter(lambda port: port.vid is not None and port.vid not in blacklistVids,
|
||||
serial.tools.list_ports.comports())))
|
||||
l.sort()
|
||||
return l
|
||||
|
||||
|
||||
class dotdict(dict):
|
||||
"""dot.notation access to dictionary attributes"""
|
||||
__getattr__ = dict.get
|
||||
__setattr__ = dict.__setitem__
|
||||
__delattr__ = dict.__delitem__
|
||||
|
||||
|
||||
class Timeout:
|
||||
"""Timeout class"""
|
||||
def __init__(self, maxSecs=20):
|
||||
self.expireTime = 0
|
||||
self.sleepInterval = 0.1
|
||||
self.expireTimeout = maxSecs
|
||||
|
||||
def reset(self):
|
||||
"""Restart the waitForSet timer"""
|
||||
self.expireTime = time.time() + self.expireTimeout
|
||||
|
||||
def waitForSet(self, target, attrs=()):
|
||||
"""Block until the specified attributes are set. Returns True if config has been received."""
|
||||
self.reset()
|
||||
while time.time() < self.expireTime:
|
||||
if all(map(lambda a: getattr(target, a, None), attrs)):
|
||||
return True
|
||||
time.sleep(self.sleepInterval)
|
||||
return False
|
||||
|
||||
|
||||
class DeferredExecution():
|
||||
"""A thread that accepts closures to run, and runs them as they are received"""
|
||||
|
||||
def __init__(self, name=None):
|
||||
self.queue = Queue()
|
||||
self.thread = threading.Thread(target=self._run, args=(), name=name)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
|
||||
def queueWork(self, runnable):
|
||||
""" Queue up the work"""
|
||||
self.queue.put(runnable)
|
||||
|
||||
def _run(self):
|
||||
while True:
|
||||
try:
|
||||
o = self.queue.get()
|
||||
o()
|
||||
except:
|
||||
logging.error(
|
||||
f"Unexpected error in deferred execution {sys.exc_info()[0]}")
|
||||
print(traceback.format_exc())
|
||||
|
||||
|
||||
def our_exit(message, return_value = 1):
|
||||
"""Print the message and return a value.
|
||||
return_value defaults to 1 (non-successful)
|
||||
"""
|
||||
print(message)
|
||||
sys.exit(return_value)
|
||||
|
||||
|
||||
def support_info():
|
||||
"""Print out info that helps troubleshooting of the cli."""
|
||||
print('')
|
||||
print('If having issues with meshtastic cli or python library')
|
||||
print('or wish to make feature requests, visit:')
|
||||
print('https://github.com/meshtastic/Meshtastic-python/issues')
|
||||
print('When adding an issue, be sure to include the following info:')
|
||||
print(' System: {0}'.format(platform.system()))
|
||||
print(' Platform: {0}'.format(platform.platform()))
|
||||
print(' Release: {0}'.format(platform.uname().release))
|
||||
print(' Machine: {0}'.format(platform.uname().machine))
|
||||
print(' Encoding (stdin): {0}'.format(sys.stdin.encoding))
|
||||
print(' Encoding (stdout): {0}'.format(sys.stdout.encoding))
|
||||
print(' meshtastic: v{0}'.format(pkg_resources.require('meshtastic')[0].version))
|
||||
print(' Executable: {0}'.format(sys.argv[0]))
|
||||
print(' Python: {0} {1} {2}'.format(platform.python_version(),
|
||||
platform.python_implementation(), platform.python_compiler()))
|
||||
print('')
|
||||
print('Please add the output from the command: meshtastic --info')</code></pre>
|
||||
</details>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.util.catchAndIgnore"><code class="name flex">
|
||||
<span>def <span class="ident">catchAndIgnore</span></span>(<span>reason, closure)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Call a closure but if it throws an exception print it and continue</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def catchAndIgnore(reason, closure):
|
||||
"""Call a closure but if it throws an exception print it and continue"""
|
||||
try:
|
||||
closure()
|
||||
except BaseException as ex:
|
||||
logging.error(f"Exception thrown in {reason}: {ex}")</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.findPorts"><code class="name flex">
|
||||
<span>def <span class="ident">findPorts</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Find all ports that might have meshtastic devices</p>
|
||||
<h2 id="returns">Returns</h2>
|
||||
<p>list – a list of device paths</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def findPorts():
|
||||
"""Find all ports that might have meshtastic devices
|
||||
|
||||
Returns:
|
||||
list -- a list of device paths
|
||||
"""
|
||||
l = list(map(lambda port: port.device,
|
||||
filter(lambda port: port.vid is not None and port.vid not in blacklistVids,
|
||||
serial.tools.list_ports.comports())))
|
||||
l.sort()
|
||||
return l</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.fixme"><code class="name flex">
|
||||
<span>def <span class="ident">fixme</span></span>(<span>message)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Raise an exception for things that needs to be fixed</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def fixme(message):
|
||||
"""Raise an exception for things that needs to be fixed"""
|
||||
raise Exception(f"FIXME: {message}")</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.fromPSK"><code class="name flex">
|
||||
<span>def <span class="ident">fromPSK</span></span>(<span>valstr)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A special version of fromStr that assumes the user is trying to set a PSK.
|
||||
In that case we also allow "none", "default" or "random" (to have python generate one), or simpleN</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def fromPSK(valstr):
|
||||
"""A special version of fromStr that assumes the user is trying to set a PSK.
|
||||
In that case we also allow "none", "default" or "random" (to have python generate one), or simpleN
|
||||
"""
|
||||
if valstr == "random":
|
||||
return genPSK256()
|
||||
elif valstr == "none":
|
||||
return bytes([0]) # Use the 'no encryption' PSK
|
||||
elif valstr == "default":
|
||||
return bytes([1]) # Use default channel psk
|
||||
elif valstr.startswith("simple"):
|
||||
# Use one of the single byte encodings
|
||||
return bytes([int(valstr[6:]) + 1])
|
||||
else:
|
||||
return fromStr(valstr)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.fromStr"><code class="name flex">
|
||||
<span>def <span class="ident">fromStr</span></span>(<span>valstr)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Try to parse as int, float or bool (and fallback to a string as last resort)</p>
|
||||
<p>Returns: an int, bool, float, str or byte array (for strings of hex digits)</p>
|
||||
<h2 id="args">Args</h2>
|
||||
<dl>
|
||||
<dt><strong><code>valstr</code></strong> : <code>string</code></dt>
|
||||
<dd>A user provided string</dd>
|
||||
</dl></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def fromStr(valstr):
|
||||
"""Try to parse as int, float or bool (and fallback to a string as last resort)
|
||||
|
||||
Returns: an int, bool, float, str or byte array (for strings of hex digits)
|
||||
|
||||
Args:
|
||||
valstr (string): A user provided string
|
||||
"""
|
||||
if len(valstr) == 0: # Treat an emptystring as an empty bytes
|
||||
val = bytes()
|
||||
elif valstr.startswith('0x'):
|
||||
# if needed convert to string with asBytes.decode('utf-8')
|
||||
val = bytes.fromhex(valstr[2:])
|
||||
elif valstr.lower() in {"t", "true", "yes"}:
|
||||
val = True
|
||||
elif valstr.lower() in {"f", "false", "no"}:
|
||||
val = False
|
||||
else:
|
||||
try:
|
||||
val = int(valstr)
|
||||
except ValueError:
|
||||
try:
|
||||
val = float(valstr)
|
||||
except ValueError:
|
||||
val = valstr # Not a float or an int, assume string
|
||||
return val</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.genPSK256"><code class="name flex">
|
||||
<span>def <span class="ident">genPSK256</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Generate a random preshared key</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def genPSK256():
|
||||
"""Generate a random preshared key"""
|
||||
return os.urandom(32)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.our_exit"><code class="name flex">
|
||||
<span>def <span class="ident">our_exit</span></span>(<span>message, return_value=1)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Print the message and return a value.
|
||||
return_value defaults to 1 (non-successful)</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def our_exit(message, return_value = 1):
|
||||
"""Print the message and return a value.
|
||||
return_value defaults to 1 (non-successful)
|
||||
"""
|
||||
print(message)
|
||||
sys.exit(return_value)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.pskToString"><code class="name flex">
|
||||
<span>def <span class="ident">pskToString</span></span>(<span>psk: bytes)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def pskToString(psk: bytes):
|
||||
"""Given an array of PSK bytes, decode them into a human readable (but privacy protecting) string"""
|
||||
if len(psk) == 0:
|
||||
return "unencrypted"
|
||||
elif len(psk) == 1:
|
||||
b = psk[0]
|
||||
if b == 0:
|
||||
return "unencrypted"
|
||||
elif b == 1:
|
||||
return "default"
|
||||
else:
|
||||
return f"simple{b - 1}"
|
||||
else:
|
||||
return "secret"</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.quoteBooleans"><code class="name flex">
|
||||
<span>def <span class="ident">quoteBooleans</span></span>(<span>a_string)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Quote booleans
|
||||
given a string that contains ": true", replace with ": 'true'" (or false)</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def quoteBooleans(a_string):
|
||||
"""Quote booleans
|
||||
given a string that contains ": true", replace with ": 'true'" (or false)
|
||||
"""
|
||||
tmp = a_string.replace(": true", ": 'true'")
|
||||
tmp = tmp.replace(": false", ": 'false'")
|
||||
return tmp</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.stripnl"><code class="name flex">
|
||||
<span>def <span class="ident">stripnl</span></span>(<span>s)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Remove newlines from a string (and remove extra whitespace)</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def stripnl(s):
|
||||
"""Remove newlines from a string (and remove extra whitespace)"""
|
||||
s = str(s).replace("\n", " ")
|
||||
return ' '.join(s.split())</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.support_info"><code class="name flex">
|
||||
<span>def <span class="ident">support_info</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Print out info that helps troubleshooting of the cli.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def support_info():
|
||||
"""Print out info that helps troubleshooting of the cli."""
|
||||
print('')
|
||||
print('If having issues with meshtastic cli or python library')
|
||||
print('or wish to make feature requests, visit:')
|
||||
print('https://github.com/meshtastic/Meshtastic-python/issues')
|
||||
print('When adding an issue, be sure to include the following info:')
|
||||
print(' System: {0}'.format(platform.system()))
|
||||
print(' Platform: {0}'.format(platform.platform()))
|
||||
print(' Release: {0}'.format(platform.uname().release))
|
||||
print(' Machine: {0}'.format(platform.uname().machine))
|
||||
print(' Encoding (stdin): {0}'.format(sys.stdin.encoding))
|
||||
print(' Encoding (stdout): {0}'.format(sys.stdout.encoding))
|
||||
print(' meshtastic: v{0}'.format(pkg_resources.require('meshtastic')[0].version))
|
||||
print(' Executable: {0}'.format(sys.argv[0]))
|
||||
print(' Python: {0} {1} {2}'.format(platform.python_version(),
|
||||
platform.python_implementation(), platform.python_compiler()))
|
||||
print('')
|
||||
print('Please add the output from the command: meshtastic --info')</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="meshtastic.util.DeferredExecution"><code class="flex name class">
|
||||
<span>class <span class="ident">DeferredExecution</span></span>
|
||||
<span>(</span><span>name=None)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>A thread that accepts closures to run, and runs them as they are received</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class DeferredExecution():
|
||||
"""A thread that accepts closures to run, and runs them as they are received"""
|
||||
|
||||
def __init__(self, name=None):
|
||||
self.queue = Queue()
|
||||
self.thread = threading.Thread(target=self._run, args=(), name=name)
|
||||
self.thread.daemon = True
|
||||
self.thread.start()
|
||||
|
||||
def queueWork(self, runnable):
|
||||
""" Queue up the work"""
|
||||
self.queue.put(runnable)
|
||||
|
||||
def _run(self):
|
||||
while True:
|
||||
try:
|
||||
o = self.queue.get()
|
||||
o()
|
||||
except:
|
||||
logging.error(
|
||||
f"Unexpected error in deferred execution {sys.exc_info()[0]}")
|
||||
print(traceback.format_exc())</code></pre>
|
||||
</details>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.util.DeferredExecution.queueWork"><code class="name flex">
|
||||
<span>def <span class="ident">queueWork</span></span>(<span>self, runnable)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Queue up the work</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def queueWork(self, runnable):
|
||||
""" Queue up the work"""
|
||||
self.queue.put(runnable)</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.Timeout"><code class="flex name class">
|
||||
<span>class <span class="ident">Timeout</span></span>
|
||||
<span>(</span><span>maxSecs=20)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Timeout class</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class Timeout:
|
||||
"""Timeout class"""
|
||||
def __init__(self, maxSecs=20):
|
||||
self.expireTime = 0
|
||||
self.sleepInterval = 0.1
|
||||
self.expireTimeout = maxSecs
|
||||
|
||||
def reset(self):
|
||||
"""Restart the waitForSet timer"""
|
||||
self.expireTime = time.time() + self.expireTimeout
|
||||
|
||||
def waitForSet(self, target, attrs=()):
|
||||
"""Block until the specified attributes are set. Returns True if config has been received."""
|
||||
self.reset()
|
||||
while time.time() < self.expireTime:
|
||||
if all(map(lambda a: getattr(target, a, None), attrs)):
|
||||
return True
|
||||
time.sleep(self.sleepInterval)
|
||||
return False</code></pre>
|
||||
</details>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="meshtastic.util.Timeout.reset"><code class="name flex">
|
||||
<span>def <span class="ident">reset</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Restart the waitForSet timer</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def reset(self):
|
||||
"""Restart the waitForSet timer"""
|
||||
self.expireTime = time.time() + self.expireTimeout</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.Timeout.waitForSet"><code class="name flex">
|
||||
<span>def <span class="ident">waitForSet</span></span>(<span>self, target, attrs=())</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Block until the specified attributes are set. Returns True if config has been received.</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def waitForSet(self, target, attrs=()):
|
||||
"""Block until the specified attributes are set. Returns True if config has been received."""
|
||||
self.reset()
|
||||
while time.time() < self.expireTime:
|
||||
if all(map(lambda a: getattr(target, a, None), attrs)):
|
||||
return True
|
||||
time.sleep(self.sleepInterval)
|
||||
return False</code></pre>
|
||||
</details>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="meshtastic.util.dotdict"><code class="flex name class">
|
||||
<span>class <span class="ident">dotdict</span></span>
|
||||
<span>(</span><span>*args, **kwargs)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>dot.notation access to dictionary attributes</p></div>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class dotdict(dict):
|
||||
"""dot.notation access to dictionary attributes"""
|
||||
__getattr__ = dict.get
|
||||
__setattr__ = dict.__setitem__
|
||||
__delattr__ = dict.__delitem__</code></pre>
|
||||
</details>
|
||||
<h3>Ancestors</h3>
|
||||
<ul class="hlist">
|
||||
<li>builtins.dict</li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
</article>
|
||||
<nav id="sidebar">
|
||||
<h1>Index</h1>
|
||||
<div class="toc">
|
||||
<ul></ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3>Super-module</h3>
|
||||
<ul>
|
||||
<li><code><a title="meshtastic" href="index.html">meshtastic</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-functions">Functions</a></h3>
|
||||
<ul class="two-column">
|
||||
<li><code><a title="meshtastic.util.catchAndIgnore" href="#meshtastic.util.catchAndIgnore">catchAndIgnore</a></code></li>
|
||||
<li><code><a title="meshtastic.util.findPorts" href="#meshtastic.util.findPorts">findPorts</a></code></li>
|
||||
<li><code><a title="meshtastic.util.fixme" href="#meshtastic.util.fixme">fixme</a></code></li>
|
||||
<li><code><a title="meshtastic.util.fromPSK" href="#meshtastic.util.fromPSK">fromPSK</a></code></li>
|
||||
<li><code><a title="meshtastic.util.fromStr" href="#meshtastic.util.fromStr">fromStr</a></code></li>
|
||||
<li><code><a title="meshtastic.util.genPSK256" href="#meshtastic.util.genPSK256">genPSK256</a></code></li>
|
||||
<li><code><a title="meshtastic.util.our_exit" href="#meshtastic.util.our_exit">our_exit</a></code></li>
|
||||
<li><code><a title="meshtastic.util.pskToString" href="#meshtastic.util.pskToString">pskToString</a></code></li>
|
||||
<li><code><a title="meshtastic.util.quoteBooleans" href="#meshtastic.util.quoteBooleans">quoteBooleans</a></code></li>
|
||||
<li><code><a title="meshtastic.util.stripnl" href="#meshtastic.util.stripnl">stripnl</a></code></li>
|
||||
<li><code><a title="meshtastic.util.support_info" href="#meshtastic.util.support_info">support_info</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.util.DeferredExecution" href="#meshtastic.util.DeferredExecution">DeferredExecution</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.util.DeferredExecution.queueWork" href="#meshtastic.util.DeferredExecution.queueWork">queueWork</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.util.Timeout" href="#meshtastic.util.Timeout">Timeout</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="meshtastic.util.Timeout.reset" href="#meshtastic.util.Timeout.reset">reset</a></code></li>
|
||||
<li><code><a title="meshtastic.util.Timeout.waitForSet" href="#meshtastic.util.Timeout.waitForSet">waitForSet</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="meshtastic.util.dotdict" href="#meshtastic.util.dotdict">dotdict</a></code></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</main>
|
||||
<footer id="footer">
|
||||
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -567,6 +567,7 @@ def export_config(interface):
|
||||
|
||||
def common():
|
||||
"""Shared code for all of our command line wrappers"""
|
||||
logfile = None
|
||||
our_globals = Globals.getInstance()
|
||||
args = our_globals.get_args()
|
||||
parser = our_globals.get_parser()
|
||||
@@ -621,8 +622,8 @@ def common():
|
||||
logging.info(f"Logging serial output to {args.seriallog}")
|
||||
# Note: using "line buffering"
|
||||
# pylint: disable=R1732
|
||||
logfile = open(args.seriallog, 'w+',
|
||||
buffering=1, encoding='utf8')
|
||||
logfile = open(args.seriallog, 'w+', buffering=1, encoding='utf8')
|
||||
our_globals.set_logfile(logfile)
|
||||
|
||||
subscribe()
|
||||
if args.ble:
|
||||
@@ -636,6 +637,8 @@ def common():
|
||||
|
||||
# We assume client is fully connected now
|
||||
onConnected(client)
|
||||
#if logfile:
|
||||
#logfile.close()
|
||||
|
||||
if args.noproto or (have_tunnel and args.tunnel): # loop until someone presses ctrlc
|
||||
while True:
|
||||
@@ -828,6 +831,10 @@ def main():
|
||||
our_globals.set_parser(parser)
|
||||
initParser()
|
||||
common()
|
||||
logfile = our_globals.get_logfile()
|
||||
if logfile:
|
||||
logfile.close()
|
||||
|
||||
|
||||
|
||||
def tunnelMain():
|
||||
|
||||
@@ -12,8 +12,8 @@ _sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from . import channel_pb2 as channel__pb2
|
||||
from . import mesh_pb2 as mesh__pb2
|
||||
from . import radioconfig_pb2 as radioconfig__pb2
|
||||
from . import mesh_pb2 as mesh__pb2
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
@@ -21,9 +21,9 @@ DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
package='',
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\023com.geeksville.meshB\013AdminProtosH\003Z!github.com/meshtastic/gomeshproto',
|
||||
serialized_pb=b'\n\x0b\x61\x64min.proto\x1a\rchannel.proto\x1a\nmesh.proto\x1a\x11radioconfig.proto\"\xfb\x02\n\x0c\x41\x64minMessage\x12!\n\tset_radio\x18\x01 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1a\n\tset_owner\x18\x02 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18\x03 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_radio_request\x18\x04 \x01(\x08H\x00\x12*\n\x12get_radio_response\x18\x05 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1d\n\x13get_channel_request\x18\x06 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x07 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1d\n\x13\x63onfirm_set_channel\x18 \x01(\x08H\x00\x12\x1b\n\x11\x63onfirm_set_radio\x18! \x01(\x08H\x00\x12\x18\n\x0e\x65xit_simulator\x18\" \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18# \x01(\x05H\x00\x42\t\n\x07variantBG\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
|
||||
serialized_pb=b'\n\x0b\x61\x64min.proto\x1a\rchannel.proto\x1a\x11radioconfig.proto\x1a\nmesh.proto\"\xbd\x03\n\x0c\x41\x64minMessage\x12!\n\tset_radio\x18\x01 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1a\n\tset_owner\x18\x02 \x01(\x0b\x32\x05.UserH\x00\x12\x1f\n\x0bset_channel\x18\x03 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_radio_request\x18\x04 \x01(\x08H\x00\x12*\n\x12get_radio_response\x18\x05 \x01(\x0b\x32\x0c.RadioConfigH\x00\x12\x1d\n\x13get_channel_request\x18\x06 \x01(\rH\x00\x12(\n\x14get_channel_response\x18\x07 \x01(\x0b\x32\x08.ChannelH\x00\x12\x1b\n\x11get_owner_request\x18\x08 \x01(\x08H\x00\x12#\n\x12get_owner_response\x18\t \x01(\x0b\x32\x05.UserH\x00\x12\x1d\n\x13\x63onfirm_set_channel\x18 \x01(\x08H\x00\x12\x1b\n\x11\x63onfirm_set_radio\x18! \x01(\x08H\x00\x12\x18\n\x0e\x65xit_simulator\x18\" \x01(\x08H\x00\x12\x18\n\x0ereboot_seconds\x18# \x01(\x05H\x00\x42\t\n\x07variantBG\n\x13\x63om.geeksville.meshB\x0b\x41\x64minProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
|
||||
,
|
||||
dependencies=[channel__pb2.DESCRIPTOR,mesh__pb2.DESCRIPTOR,radioconfig__pb2.DESCRIPTOR,])
|
||||
dependencies=[channel__pb2.DESCRIPTOR,radioconfig__pb2.DESCRIPTOR,mesh__pb2.DESCRIPTOR,])
|
||||
|
||||
|
||||
|
||||
@@ -85,28 +85,42 @@ _ADMINMESSAGE = _descriptor.Descriptor(
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='confirm_set_channel', full_name='AdminMessage.confirm_set_channel', index=7,
|
||||
name='get_owner_request', full_name='AdminMessage.get_owner_request', index=7,
|
||||
number=8, type=8, cpp_type=7, label=1,
|
||||
has_default_value=False, default_value=False,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='get_owner_response', full_name='AdminMessage.get_owner_response', index=8,
|
||||
number=9, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='confirm_set_channel', full_name='AdminMessage.confirm_set_channel', index=9,
|
||||
number=32, type=8, cpp_type=7, label=1,
|
||||
has_default_value=False, default_value=False,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='confirm_set_radio', full_name='AdminMessage.confirm_set_radio', index=8,
|
||||
name='confirm_set_radio', full_name='AdminMessage.confirm_set_radio', index=10,
|
||||
number=33, type=8, cpp_type=7, label=1,
|
||||
has_default_value=False, default_value=False,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='exit_simulator', full_name='AdminMessage.exit_simulator', index=9,
|
||||
name='exit_simulator', full_name='AdminMessage.exit_simulator', index=11,
|
||||
number=34, type=8, cpp_type=7, label=1,
|
||||
has_default_value=False, default_value=False,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='reboot_seconds', full_name='AdminMessage.reboot_seconds', index=10,
|
||||
name='reboot_seconds', full_name='AdminMessage.reboot_seconds', index=12,
|
||||
number=35, type=5, cpp_type=1, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
@@ -128,7 +142,7 @@ _ADMINMESSAGE = _descriptor.Descriptor(
|
||||
index=0, containing_type=None, fields=[]),
|
||||
],
|
||||
serialized_start=62,
|
||||
serialized_end=441,
|
||||
serialized_end=507,
|
||||
)
|
||||
|
||||
_ADMINMESSAGE.fields_by_name['set_radio'].message_type = radioconfig__pb2._RADIOCONFIG
|
||||
@@ -136,6 +150,7 @@ _ADMINMESSAGE.fields_by_name['set_owner'].message_type = mesh__pb2._USER
|
||||
_ADMINMESSAGE.fields_by_name['set_channel'].message_type = channel__pb2._CHANNEL
|
||||
_ADMINMESSAGE.fields_by_name['get_radio_response'].message_type = radioconfig__pb2._RADIOCONFIG
|
||||
_ADMINMESSAGE.fields_by_name['get_channel_response'].message_type = channel__pb2._CHANNEL
|
||||
_ADMINMESSAGE.fields_by_name['get_owner_response'].message_type = mesh__pb2._USER
|
||||
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
|
||||
_ADMINMESSAGE.fields_by_name['set_radio'])
|
||||
_ADMINMESSAGE.fields_by_name['set_radio'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
|
||||
@@ -157,6 +172,12 @@ _ADMINMESSAGE.fields_by_name['get_channel_request'].containing_oneof = _ADMINMES
|
||||
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
|
||||
_ADMINMESSAGE.fields_by_name['get_channel_response'])
|
||||
_ADMINMESSAGE.fields_by_name['get_channel_response'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
|
||||
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
|
||||
_ADMINMESSAGE.fields_by_name['get_owner_request'])
|
||||
_ADMINMESSAGE.fields_by_name['get_owner_request'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
|
||||
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
|
||||
_ADMINMESSAGE.fields_by_name['get_owner_response'])
|
||||
_ADMINMESSAGE.fields_by_name['get_owner_response'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
|
||||
_ADMINMESSAGE.oneofs_by_name['variant'].fields.append(
|
||||
_ADMINMESSAGE.fields_by_name['confirm_set_channel'])
|
||||
_ADMINMESSAGE.fields_by_name['confirm_set_channel'].containing_oneof = _ADMINMESSAGE.oneofs_by_name['variant']
|
||||
|
||||
@@ -29,6 +29,7 @@ class Globals:
|
||||
self.parser = None
|
||||
self.target_node = None
|
||||
self.channel_index = None
|
||||
self.logfile = None
|
||||
|
||||
def reset(self):
|
||||
"""Reset all of our globals. If you add a member, add it to this method, too."""
|
||||
@@ -37,6 +38,7 @@ class Globals:
|
||||
self.target_node = None
|
||||
self.channel_index = None
|
||||
|
||||
# setters
|
||||
def set_args(self, args):
|
||||
"""Set the args"""
|
||||
self.args = args
|
||||
@@ -53,6 +55,11 @@ class Globals:
|
||||
"""Set the channel_index"""
|
||||
self.channel_index = channel_index
|
||||
|
||||
def set_logfile(self, logfile):
|
||||
"""Set the logfile"""
|
||||
self.logfile = logfile
|
||||
|
||||
# getters
|
||||
def get_args(self):
|
||||
"""Get args"""
|
||||
return self.args
|
||||
@@ -68,3 +75,7 @@ class Globals:
|
||||
def get_channel_index(self):
|
||||
"""Get channel_index"""
|
||||
return self.channel_index
|
||||
|
||||
def get_logfile(self):
|
||||
"""Get logfile"""
|
||||
return self.logfile
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,14 +1,16 @@
|
||||
""" Serial interface class
|
||||
"""
|
||||
import logging
|
||||
import time
|
||||
import platform
|
||||
import os
|
||||
import stat
|
||||
import serial
|
||||
|
||||
import meshtastic.util
|
||||
from .stream_interface import StreamInterface
|
||||
|
||||
if platform.system() != 'Windows':
|
||||
import termios
|
||||
|
||||
class SerialInterface(StreamInterface):
|
||||
"""Interface class for meshtastic devices over a serial link"""
|
||||
|
||||
@@ -20,6 +22,7 @@ class SerialInterface(StreamInterface):
|
||||
devPath {string} -- A filepath to a device, i.e. /dev/ttyUSB0 (default: {None})
|
||||
debugOut {stream} -- If a stream is provided, any debug serial output from the device will be emitted to that stream. (default: {None})
|
||||
"""
|
||||
self.noProto = noProto
|
||||
|
||||
if devPath is None:
|
||||
ports = meshtastic.util.findPorts()
|
||||
@@ -35,43 +38,30 @@ class SerialInterface(StreamInterface):
|
||||
|
||||
logging.debug(f"Connecting to {devPath}")
|
||||
|
||||
# Note: we provide None for port here, because we will be opening it later
|
||||
self.stream = serial.Serial(
|
||||
None, 921600, exclusive=True, timeout=0.5, write_timeout=0)
|
||||
# first we need to set the HUPCL so the device will not reboot based on RTS and/or DTR
|
||||
# see https://github.com/pyserial/pyserial/issues/124
|
||||
if not self.noProto:
|
||||
if platform.system() != 'Windows':
|
||||
with open(devPath, encoding='utf8') as f:
|
||||
attrs = termios.tcgetattr(f)
|
||||
attrs[2] = attrs[2] & ~termios.HUPCL
|
||||
termios.tcsetattr(f, termios.TCSAFLUSH, attrs)
|
||||
f.close()
|
||||
time.sleep(0.1)
|
||||
|
||||
# rts=False Needed to prevent TBEAMs resetting on OSX, because rts is connected to reset
|
||||
self.stream.port = devPath
|
||||
self.stream = serial.Serial(devPath, 921600, exclusive=True, timeout=0.5, write_timeout=0)
|
||||
if not self.noProto:
|
||||
self.stream.flush()
|
||||
time.sleep(0.1)
|
||||
|
||||
# HACK: If the platform driving the serial port is unable to leave the RTS pin in high-impedance
|
||||
# mode, set RTS to false so that the device platform won't be reset spuriously.
|
||||
# Linux does this properly, so don't apply this hack on Linux (because it makes the reset button not work).
|
||||
if self._hostPlatformAlwaysDrivesUartRts():
|
||||
self.stream.rts = False
|
||||
self.stream.open()
|
||||
StreamInterface.__init__(self, debugOut=debugOut, noProto=noProto, connectNow=connectNow)
|
||||
|
||||
StreamInterface.__init__(
|
||||
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow)
|
||||
|
||||
"""true if platform driving the serial port is Windows Subsystem for Linux 1."""
|
||||
def _isWsl1(self):
|
||||
# WSL1 identifies itself as Linux, but has a special char device at /dev/lxss for use with session control,
|
||||
# e.g. /init. We should treat WSL1 as Windows for the RTS-driving hack because the underlying platfrom
|
||||
# serial driver for the CP21xx still exhibits the buggy behavior.
|
||||
# WSL2 is not covered here, as it does not (as of 2021-May-25) support the appropriate functionality to
|
||||
# share or pass-through serial ports.
|
||||
try:
|
||||
# Claims to be Linux, but has /dev/lxss; must be WSL 1
|
||||
return platform.system() == 'Linux' and stat.S_ISCHR(os.stat('/dev/lxss').st_mode)
|
||||
except:
|
||||
# Couldn't stat /dev/lxss special device; not WSL1
|
||||
return False
|
||||
|
||||
def _hostPlatformAlwaysDrivesUartRts(self):
|
||||
# OS-X/Windows seems to have a bug in its CP21xx serial drivers. It ignores that we asked for no RTSCTS
|
||||
# control and will always drive RTS either high or low (rather than letting the CP102 leave
|
||||
# it as an open-collector floating pin).
|
||||
# TODO: When WSL2 supports USB passthrough, this will get messier. If/when WSL2 gets virtual serial
|
||||
# ports that "share" the Windows serial port (and thus the Windows drivers), this code will need to be
|
||||
# updated to reflect that as well -- or if T-Beams get made with an alternate USB to UART bridge that has
|
||||
# a less buggy driver.
|
||||
return platform.system() != 'Linux' or self._isWsl1()
|
||||
def close(self):
|
||||
"""Close a connection to the device"""
|
||||
if not self.noProto:
|
||||
self.stream.flush()
|
||||
time.sleep(0.1)
|
||||
self.stream.flush()
|
||||
time.sleep(0.1)
|
||||
logging.debug("Closing Serial stream")
|
||||
StreamInterface.close(self)
|
||||
|
||||
@@ -18,7 +18,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
|
||||
package='',
|
||||
syntax='proto3',
|
||||
serialized_options=b'\n\023com.geeksville.meshB\025StoreAndForwardProtosH\003Z!github.com/meshtastic/gomeshproto',
|
||||
serialized_pb=b'\n\x12storeforward.proto\"\xe7\x04\n\x0fStoreAndForward\x12,\n\x02rr\x18\x01 \x01(\x0e\x32 .StoreAndForward.RequestResponse\x12*\n\x05stats\x18\x02 \x01(\x0b\x32\x1b.StoreAndForward.Statistics\x12)\n\x07history\x18\x03 \x01(\x0b\x32\x18.StoreAndForward.History\x1a\xc6\x01\n\nStatistics\x12\x15\n\rMessagesTotal\x18\x01 \x01(\r\x12\x15\n\rMessagesSaved\x18\x02 \x01(\r\x12\x13\n\x0bMessagesMax\x18\x03 \x01(\r\x12\x0e\n\x06UpTime\x18\x04 \x01(\r\x12\x10\n\x08Requests\x18\x05 \x01(\r\x12\x17\n\x0fRequestsHistory\x18\x06 \x01(\r\x12\x11\n\tHeartbeat\x18\x07 \x01(\x08\x12\x11\n\tReturnMax\x18\x08 \x01(\r\x12\x14\n\x0cReturnWindow\x18\t \x01(\r\x1a\x32\n\x07History\x12\x17\n\x0fHistoryMessages\x18\x01 \x01(\r\x12\x0e\n\x06Window\x18\x02 \x01(\r\"\xd1\x01\n\x0fRequestResponse\x12\t\n\x05UNSET\x10\x00\x12\x10\n\x0cROUTER_ERROR\x10\x01\x12\x14\n\x10ROUTER_HEARTBEAT\x10\x02\x12\x0f\n\x0bROUTER_PING\x10\x03\x12\x0f\n\x0bROUTER_PONG\x10\x04\x12\x0f\n\x0bROUTER_BUSY\x10\x05\x12\x10\n\x0c\x43LIENT_ERROR\x10\x65\x12\x12\n\x0e\x43LIENT_HISTORY\x10\x66\x12\x10\n\x0c\x43LIENT_STATS\x10g\x12\x0f\n\x0b\x43LIENT_PING\x10h\x12\x0f\n\x0b\x43LIENT_PONG\x10iBQ\n\x13\x63om.geeksville.meshB\x15StoreAndForwardProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
|
||||
serialized_pb=b'\n\x12storeforward.proto\"\x8a\x06\n\x0fStoreAndForward\x12,\n\x02rr\x18\x01 \x01(\x0e\x32 .StoreAndForward.RequestResponse\x12*\n\x05stats\x18\x02 \x01(\x0b\x32\x1b.StoreAndForward.Statistics\x12)\n\x07history\x18\x03 \x01(\x0b\x32\x18.StoreAndForward.History\x12-\n\theartbeat\x18\x04 \x01(\x0b\x32\x1a.StoreAndForward.Heartbeat\x1a\xcd\x01\n\nStatistics\x12\x16\n\x0emessages_total\x18\x01 \x01(\r\x12\x16\n\x0emessages_saved\x18\x02 \x01(\r\x12\x14\n\x0cmessages_max\x18\x03 \x01(\r\x12\x0f\n\x07up_time\x18\x04 \x01(\r\x12\x10\n\x08requests\x18\x05 \x01(\r\x12\x18\n\x10requests_history\x18\x06 \x01(\r\x12\x11\n\theartbeat\x18\x07 \x01(\x08\x12\x12\n\nreturn_max\x18\x08 \x01(\r\x12\x15\n\rreturn_window\x18\t \x01(\r\x1aI\n\x07History\x12\x18\n\x10history_messages\x18\x01 \x01(\r\x12\x0e\n\x06window\x18\x02 \x01(\r\x12\x14\n\x0clast_request\x18\x03 \x01(\r\x1a.\n\tHeartbeat\x12\x0e\n\x06period\x18\x01 \x01(\r\x12\x11\n\tsecondary\x18\x02 \x01(\r\"\xf7\x01\n\x0fRequestResponse\x12\t\n\x05UNSET\x10\x00\x12\x10\n\x0cROUTER_ERROR\x10\x01\x12\x14\n\x10ROUTER_HEARTBEAT\x10\x02\x12\x0f\n\x0bROUTER_PING\x10\x03\x12\x0f\n\x0bROUTER_PONG\x10\x04\x12\x0f\n\x0bROUTER_BUSY\x10\x05\x12\x12\n\x0eROUTER_HISTORY\x10\x06\x12\x10\n\x0c\x43LIENT_ERROR\x10\x65\x12\x12\n\x0e\x43LIENT_HISTORY\x10\x66\x12\x10\n\x0c\x43LIENT_STATS\x10g\x12\x0f\n\x0b\x43LIENT_PING\x10h\x12\x0f\n\x0b\x43LIENT_PONG\x10i\x12\x10\n\x0c\x43LIENT_ABORT\x10jBQ\n\x13\x63om.geeksville.meshB\x15StoreAndForwardProtosH\x03Z!github.com/meshtastic/gomeshprotob\x06proto3'
|
||||
)
|
||||
|
||||
|
||||
@@ -54,30 +54,38 @@ _STOREANDFORWARD_REQUESTRESPONSE = _descriptor.EnumDescriptor(
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CLIENT_ERROR', index=6, number=101,
|
||||
name='ROUTER_HISTORY', index=6, number=6,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CLIENT_HISTORY', index=7, number=102,
|
||||
name='CLIENT_ERROR', index=7, number=101,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CLIENT_STATS', index=8, number=103,
|
||||
name='CLIENT_HISTORY', index=8, number=102,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CLIENT_PING', index=9, number=104,
|
||||
name='CLIENT_STATS', index=9, number=103,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CLIENT_PONG', index=10, number=105,
|
||||
name='CLIENT_PING', index=10, number=104,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CLIENT_PONG', index=11, number=105,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
_descriptor.EnumValueDescriptor(
|
||||
name='CLIENT_ABORT', index=12, number=106,
|
||||
serialized_options=None,
|
||||
type=None),
|
||||
],
|
||||
containing_type=None,
|
||||
serialized_options=None,
|
||||
serialized_start=429,
|
||||
serialized_end=638,
|
||||
serialized_start=554,
|
||||
serialized_end=801,
|
||||
)
|
||||
_sym_db.RegisterEnumDescriptor(_STOREANDFORWARD_REQUESTRESPONSE)
|
||||
|
||||
@@ -90,63 +98,63 @@ _STOREANDFORWARD_STATISTICS = _descriptor.Descriptor(
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='MessagesTotal', full_name='StoreAndForward.Statistics.MessagesTotal', index=0,
|
||||
name='messages_total', full_name='StoreAndForward.Statistics.messages_total', index=0,
|
||||
number=1, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='MessagesSaved', full_name='StoreAndForward.Statistics.MessagesSaved', index=1,
|
||||
name='messages_saved', full_name='StoreAndForward.Statistics.messages_saved', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='MessagesMax', full_name='StoreAndForward.Statistics.MessagesMax', index=2,
|
||||
name='messages_max', full_name='StoreAndForward.Statistics.messages_max', index=2,
|
||||
number=3, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='UpTime', full_name='StoreAndForward.Statistics.UpTime', index=3,
|
||||
name='up_time', full_name='StoreAndForward.Statistics.up_time', index=3,
|
||||
number=4, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='Requests', full_name='StoreAndForward.Statistics.Requests', index=4,
|
||||
name='requests', full_name='StoreAndForward.Statistics.requests', index=4,
|
||||
number=5, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='RequestsHistory', full_name='StoreAndForward.Statistics.RequestsHistory', index=5,
|
||||
name='requests_history', full_name='StoreAndForward.Statistics.requests_history', index=5,
|
||||
number=6, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='Heartbeat', full_name='StoreAndForward.Statistics.Heartbeat', index=6,
|
||||
name='heartbeat', full_name='StoreAndForward.Statistics.heartbeat', index=6,
|
||||
number=7, type=8, cpp_type=7, label=1,
|
||||
has_default_value=False, default_value=False,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='ReturnMax', full_name='StoreAndForward.Statistics.ReturnMax', index=7,
|
||||
name='return_max', full_name='StoreAndForward.Statistics.return_max', index=7,
|
||||
number=8, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='ReturnWindow', full_name='StoreAndForward.Statistics.ReturnWindow', index=8,
|
||||
name='return_window', full_name='StoreAndForward.Statistics.return_window', index=8,
|
||||
number=9, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
@@ -164,8 +172,8 @@ _STOREANDFORWARD_STATISTICS = _descriptor.Descriptor(
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=176,
|
||||
serialized_end=374,
|
||||
serialized_start=223,
|
||||
serialized_end=428,
|
||||
)
|
||||
|
||||
_STOREANDFORWARD_HISTORY = _descriptor.Descriptor(
|
||||
@@ -176,14 +184,58 @@ _STOREANDFORWARD_HISTORY = _descriptor.Descriptor(
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='HistoryMessages', full_name='StoreAndForward.History.HistoryMessages', index=0,
|
||||
name='history_messages', full_name='StoreAndForward.History.history_messages', index=0,
|
||||
number=1, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='Window', full_name='StoreAndForward.History.Window', index=1,
|
||||
name='window', full_name='StoreAndForward.History.window', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='last_request', full_name='StoreAndForward.History.last_request', index=2,
|
||||
number=3, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[],
|
||||
enum_types=[
|
||||
],
|
||||
serialized_options=None,
|
||||
is_extendable=False,
|
||||
syntax='proto3',
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=430,
|
||||
serialized_end=503,
|
||||
)
|
||||
|
||||
_STOREANDFORWARD_HEARTBEAT = _descriptor.Descriptor(
|
||||
name='Heartbeat',
|
||||
full_name='StoreAndForward.Heartbeat',
|
||||
filename=None,
|
||||
file=DESCRIPTOR,
|
||||
containing_type=None,
|
||||
fields=[
|
||||
_descriptor.FieldDescriptor(
|
||||
name='period', full_name='StoreAndForward.Heartbeat.period', index=0,
|
||||
number=1, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='secondary', full_name='StoreAndForward.Heartbeat.secondary', index=1,
|
||||
number=2, type=13, cpp_type=3, label=1,
|
||||
has_default_value=False, default_value=0,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
@@ -201,8 +253,8 @@ _STOREANDFORWARD_HISTORY = _descriptor.Descriptor(
|
||||
extension_ranges=[],
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=376,
|
||||
serialized_end=426,
|
||||
serialized_start=505,
|
||||
serialized_end=551,
|
||||
)
|
||||
|
||||
_STOREANDFORWARD = _descriptor.Descriptor(
|
||||
@@ -233,10 +285,17 @@ _STOREANDFORWARD = _descriptor.Descriptor(
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
_descriptor.FieldDescriptor(
|
||||
name='heartbeat', full_name='StoreAndForward.heartbeat', index=3,
|
||||
number=4, type=11, cpp_type=10, label=1,
|
||||
has_default_value=False, default_value=None,
|
||||
message_type=None, enum_type=None, containing_type=None,
|
||||
is_extension=False, extension_scope=None,
|
||||
serialized_options=None, file=DESCRIPTOR),
|
||||
],
|
||||
extensions=[
|
||||
],
|
||||
nested_types=[_STOREANDFORWARD_STATISTICS, _STOREANDFORWARD_HISTORY, ],
|
||||
nested_types=[_STOREANDFORWARD_STATISTICS, _STOREANDFORWARD_HISTORY, _STOREANDFORWARD_HEARTBEAT, ],
|
||||
enum_types=[
|
||||
_STOREANDFORWARD_REQUESTRESPONSE,
|
||||
],
|
||||
@@ -247,14 +306,16 @@ _STOREANDFORWARD = _descriptor.Descriptor(
|
||||
oneofs=[
|
||||
],
|
||||
serialized_start=23,
|
||||
serialized_end=638,
|
||||
serialized_end=801,
|
||||
)
|
||||
|
||||
_STOREANDFORWARD_STATISTICS.containing_type = _STOREANDFORWARD
|
||||
_STOREANDFORWARD_HISTORY.containing_type = _STOREANDFORWARD
|
||||
_STOREANDFORWARD_HEARTBEAT.containing_type = _STOREANDFORWARD
|
||||
_STOREANDFORWARD.fields_by_name['rr'].enum_type = _STOREANDFORWARD_REQUESTRESPONSE
|
||||
_STOREANDFORWARD.fields_by_name['stats'].message_type = _STOREANDFORWARD_STATISTICS
|
||||
_STOREANDFORWARD.fields_by_name['history'].message_type = _STOREANDFORWARD_HISTORY
|
||||
_STOREANDFORWARD.fields_by_name['heartbeat'].message_type = _STOREANDFORWARD_HEARTBEAT
|
||||
_STOREANDFORWARD_REQUESTRESPONSE.containing_type = _STOREANDFORWARD
|
||||
DESCRIPTOR.message_types_by_name['StoreAndForward'] = _STOREANDFORWARD
|
||||
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||
@@ -274,6 +335,13 @@ StoreAndForward = _reflection.GeneratedProtocolMessageType('StoreAndForward', (_
|
||||
# @@protoc_insertion_point(class_scope:StoreAndForward.History)
|
||||
})
|
||||
,
|
||||
|
||||
'Heartbeat' : _reflection.GeneratedProtocolMessageType('Heartbeat', (_message.Message,), {
|
||||
'DESCRIPTOR' : _STOREANDFORWARD_HEARTBEAT,
|
||||
'__module__' : 'storeforward_pb2'
|
||||
# @@protoc_insertion_point(class_scope:StoreAndForward.Heartbeat)
|
||||
})
|
||||
,
|
||||
'DESCRIPTOR' : _STOREANDFORWARD,
|
||||
'__module__' : 'storeforward_pb2'
|
||||
# @@protoc_insertion_point(class_scope:StoreAndForward)
|
||||
@@ -281,6 +349,7 @@ StoreAndForward = _reflection.GeneratedProtocolMessageType('StoreAndForward', (_
|
||||
_sym_db.RegisterMessage(StoreAndForward)
|
||||
_sym_db.RegisterMessage(StoreAndForward.Statistics)
|
||||
_sym_db.RegisterMessage(StoreAndForward.History)
|
||||
_sym_db.RegisterMessage(StoreAndForward.Heartbeat)
|
||||
|
||||
|
||||
DESCRIPTOR._options = None
|
||||
|
||||
@@ -62,7 +62,8 @@ class StreamInterface(MeshInterface):
|
||||
# because we want to ensure it is looking for START1)
|
||||
p = bytearray([START2] * 32)
|
||||
self._writeBytes(p)
|
||||
time.sleep(0.1) # wait 100ms to give device time to start running
|
||||
if not self.noProto:
|
||||
time.sleep(0.1) # wait 100ms to give device time to start running
|
||||
|
||||
self._rxThread.start()
|
||||
|
||||
@@ -88,6 +89,9 @@ class StreamInterface(MeshInterface):
|
||||
if self.stream: # ignore writes when stream is closed
|
||||
self.stream.write(b)
|
||||
self.stream.flush()
|
||||
# we sleep here to give the TBeam a chance to work
|
||||
if not self.noProto:
|
||||
time.sleep(0.1)
|
||||
|
||||
def _readBytes(self, length):
|
||||
"""Read an array of bytes from our stream"""
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
import platform
|
||||
import os
|
||||
|
||||
# Do not like using hard coded sleeps, but it probably makes
|
||||
@@ -140,8 +141,9 @@ def test_smoke1_nodes():
|
||||
"""Test --nodes"""
|
||||
return_value, out = subprocess.getstatusoutput('meshtastic --nodes')
|
||||
assert re.match(r'Connected to radio', out)
|
||||
assert re.search(r'^│ N │ User', out, re.MULTILINE)
|
||||
assert re.search(r'^│ 1 │', out, re.MULTILINE)
|
||||
if platform.system() != 'Windows':
|
||||
assert re.search(r' User ', out, re.MULTILINE)
|
||||
assert re.search(r' 1 ', out, re.MULTILINE)
|
||||
assert return_value == 0
|
||||
|
||||
|
||||
|
||||
2
setup.py
2
setup.py
@@ -12,7 +12,7 @@ with open("README.md", "r") as fh:
|
||||
# This call to setup() does all the work
|
||||
setup(
|
||||
name="meshtastic",
|
||||
version="1.2.46",
|
||||
version="1.2.47",
|
||||
description="Python API & client shell for talking to Meshtastic devices",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
|
||||
Reference in New Issue
Block a user