├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── GoogleIOT
├── .gitignore
├── README.md
├── flash
│ ├── cert
│ │ └── .gitkeep
│ ├── config.example.py
│ ├── google_iot_core.py
│ ├── main.py
│ └── umqtt.py
└── genkey.sh
├── Makefile
├── README.md
├── deepsleep
└── deepsleep.py
├── examples
├── DS18X20
│ ├── boot.py
│ ├── main.py
│ └── onewire.py
├── OTA-lorawan
│ ├── LoraServer.py
│ ├── README.md
│ ├── config.py
│ ├── diff_match_patch.py
│ ├── firmware
│ │ ├── 1.17.0
│ │ │ └── flash
│ │ │ │ ├── OTA_INFO.py
│ │ │ │ ├── diff_match_patch.py
│ │ │ │ ├── loranet.py
│ │ │ │ ├── main.py
│ │ │ │ ├── ota.py
│ │ │ │ └── watchdog.py
│ │ └── 1.17.1
│ │ │ └── flash
│ │ │ ├── OTA_INFO.py
│ │ │ ├── diff_match_patch.py
│ │ │ ├── loranet.py
│ │ │ ├── main.py
│ │ │ ├── ota.py
│ │ │ └── watchdog.py
│ ├── groupUpdater.py
│ ├── ota.py
│ ├── requirements.txt
│ └── updaterService.py
├── OTA
│ ├── 1.0.0
│ │ └── flash
│ │ │ ├── config.py
│ │ │ ├── get_id.py
│ │ │ ├── lib
│ │ │ └── OTA.py
│ │ │ └── main.py
│ ├── 1.0.1
│ │ └── flash
│ │ │ ├── config.py
│ │ │ ├── get_id.py
│ │ │ ├── lib
│ │ │ └── OTA.py
│ │ │ └── main.py
│ ├── OTA_server.py
│ └── README.md
├── README.md
├── accelerometer_wake
│ └── main.py
├── adc
│ ├── boot.py
│ └── main.py
├── bluetooth
│ ├── boot.py
│ └── main.py
├── deepsleep
│ └── main.py
├── https
│ ├── boot.py
│ └── main.py
├── i2c
│ ├── bh1750fvi.py
│ ├── boot.py
│ └── main.py
├── lopy-lopy
│ ├── lopy-A
│ │ ├── boot.py
│ │ └── main.py
│ └── lopy-B
│ │ ├── boot.py
│ │ └── main.py
├── loraNanoGateway
│ ├── gateway
│ │ ├── boot.py
│ │ └── main.py
│ └── node
│ │ ├── boot.py
│ │ └── main.py
├── loraabp
│ ├── boot.py
│ └── main.py
├── loramac
│ ├── boot.py
│ └── main.py
├── lorawan-nano-gateway
│ ├── abp_node.py
│ ├── abp_node_US915.py
│ ├── config.py
│ ├── main.py
│ ├── nanogateway.py
│ ├── otaa_node.py
│ └── otaa_node_US915.py
├── lorawan-regional-examples
│ ├── main_AS923.py
│ ├── main_AU915.py
│ ├── main_EU868.py
│ └── main_US915.py
├── mqtt
│ ├── boot.py
│ ├── main.py
│ └── mqtt.py
├── onlineLog
│ ├── __init__.py
│ ├── boot.py
│ ├── main.py
│ └── onewire.py
├── pytrack_pysense_accelerometer
│ ├── main.py
│ └── visualiser
│ │ ├── README.md
│ │ ├── pycomLogoGoInventGrey800.png
│ │ ├── sketch.properties
│ │ └── visualiser.pyde
├── sigfoxUplink
│ ├── boot.py
│ └── main.py
└── threading
│ ├── boot.py
│ └── main.py
├── img
└── logo.png
├── lib
├── ADS1115
│ ├── ADS1115.py
│ └── boot.py
├── ALSPT19
│ └── ALSPT19.py
├── TB6612FNG
│ └── TB6612FNG.py
├── mqtt
│ └── mqtt.py
├── mqtt_aws
│ ├── MQTTClient.py
│ ├── MQTTConst.py
│ ├── MQTTDeviceShadow.py
│ ├── MQTTLib.py
│ ├── MQTTMsgHandler.py
│ └── MQTTShadowManager.py
├── onewire
│ └── onewire.py
└── sqnsupgrade
│ ├── README.md
│ ├── sqnsbr.py
│ ├── sqnsbrz.py
│ ├── sqnscodec.py
│ ├── sqnscrc.py
│ ├── sqnstp.py
│ └── sqnsupgrade.py
├── license
├── Pycom CLA Apache v1.pdf
├── Pycom FAQ v2.2.pdf
└── Pycom Licences v2.2.pdf
├── pycom-docker-fw-build
├── Dockerfile
├── README.md
└── assets
│ └── build
├── pymesh
├── mobile_app
│ ├── README.md
│ └── app-release.apk
├── pymesh_frozen
│ ├── README.md
│ ├── copy_fw.sh
│ ├── lib
│ │ ├── ble_rpc.py
│ │ ├── ble_services.py
│ │ ├── cli.py
│ │ ├── gps.py
│ │ ├── loramesh.py
│ │ ├── mesh_interface.py
│ │ ├── mesh_internal.py
│ │ ├── meshaging.py
│ │ ├── msgpack
│ │ │ ├── __init__.py
│ │ │ ├── _version.py
│ │ │ ├── exceptions.py
│ │ │ └── fallback.py
│ │ ├── pymesh.py
│ │ ├── pymesh_config.py
│ │ ├── pymesh_debug.py
│ │ └── statistics.py
│ ├── lorawan
│ │ ├── lorawan.py
│ │ └── main.py
│ ├── main-pybytes.py
│ ├── main.py
│ └── main_BR.py
└── readme.md
└── shields
├── README.md
├── lib
├── L76GNSS.py
├── LIS2HH12.py
├── LTR329ALS01.py
├── MFRC630.mpy
├── MFRC630.mpy-1.18
├── MFRC630.py
├── MPL3115A2.py
├── SI7006A20.py
├── pycoproc_1.py
└── pycoproc_2.py
├── pyscan_1.py
├── pysense_1.py
├── pysense_2.py
├── pytrack_1.py
├── pytrack_2.py
└── shield_2.py
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | When contributing to this repository, please first discuss the change you wish to make via an issue, email, or any other method with the owners of this repository before making a change.
4 |
5 | *Please note we have a Code of Conduct, please follow it in all your interactions with the project.*
6 |
7 | ## Pull Request Process
8 |
9 | 1. Update the `README.md` with details of changes to the interface, this includes new environment variables, useful file locations and container parameters.
10 | 2. Increase the version numbers in any examples files and the `README.md` to the new version that this Pull Request would represent. The versioning scheme we use is [SemVer](https://semver.org).
11 |
12 | ## Code of Conduct
13 |
14 | ### Our Pledge
15 |
16 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
17 |
18 | ### Our Standards
19 |
20 | Examples of behaviour that contributes to creating a positive environment include:
21 |
22 | * Using welcoming and inclusive language
23 | * Being respectful of differing viewpoints and experiences
24 | * Gracefully accepting constructive criticism
25 | * Focusing on what is best for the community
26 | * Showing empathy towards other community members
27 |
28 | Examples of unacceptable behaviour by participants include:
29 |
30 | * The use of sexualised language or imagery and unwelcome sexual attention or advances
31 | * Trolling, insulting/derogatory comments, and personal or political attacks
32 | * Public or private harassment
33 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
34 | * Other conduct which could reasonably be considered inappropriate in a professional setting
35 |
36 | ### Our Responsibilities
37 |
38 | Project maintainers are responsible for clarifying the standards of acceptable behaviour and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behaviour.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviours that they deem inappropriate, threatening, offensive, or harmful.
41 |
42 | ### Scope
43 |
44 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
45 |
46 | ### Enforcement
47 |
48 | Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by contacting the project team at `support[at]pycom.io` and adding the `[CoC]` tag to the subject line. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
49 |
50 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
51 |
52 | ### Attribution
53 |
54 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
55 |
56 | [homepage]: http://contributor-covenant.org
57 | [version]: http://contributor-covenant.org/version/1/4
58 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | (Hi! 👋 Thanks for reporting an issue! Please make sure you click the link above to view the issue guidelines, then fill out the blanks below.)
8 |
9 | ## What are the steps to reproduce this issue?
10 | 1.
11 | 2.
12 | 3.
13 |
14 | ## What happens?
15 |
16 |
17 | ## What were you expecting to happen?
18 |
19 |
20 | ## Any logs, error output, etc?
21 | *(If it’s long, please paste to https://gist.github.com and insert the link here)*
22 |
23 |
24 | ## Any other comments?
25 |
26 |
27 | ## What versions of software are you using?
28 | - **Board type and hardware version:**
29 | - **`os.uname()` output:**
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | # Feature Request 🚀
8 |
9 | ## Is your feature request related to a problem? Please describe.
10 | *A clear and concise description of what the problem is. E.g. I have an issue when...*
11 |
12 |
13 | ## Describe the solution you'd like
14 | *A clear and concise description of what you want to happen. Add any considered drawbacks.*
15 |
16 |
17 | ## Describe alternatives you've considered
18 | *A clear and concise description of any alternative solutions or features you've considered.*
19 |
20 |
21 | ## Teachability, Documentation, Adoption, Migration Strategy
22 | *If you can, explain how users will be able to use this and possibly write out a version the docs. Maybe a screenshot or design?*
23 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | (Hi! 👋 Thanks for sending a pull request! Please make sure you click the link above to view the contribution guidelines, then fill out the blanks below.)
2 |
3 | ## What does this implement/fix? Explain your changes.
4 |
5 |
6 | ## Does this close any currently open issues?
7 |
8 |
9 | ## Any relevant logs, error output, etc?
10 | *(If it’s long, please paste to https://gist.github.com and insert the link here)*
11 |
12 |
13 | ## Any other comments?
14 |
15 |
16 | ## Where has this been tested?
17 | - **Board type and hardware version:**
18 | - **`os.uname()` output:**
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.e6t
2 | *.e4q
3 | *.e4p
4 | *.1
5 | *.conf
6 | .DS_Store
7 |
8 | pyscan/*
9 | pysense/*
10 | pysense2/*
11 | pytrack/*
12 | pytrack2/*
13 |
14 | pyscan.zip
15 | pysense.zip
16 | pysense2.zip
17 | pytrack.zip
18 | pytrack2.zip
19 |
20 |
--------------------------------------------------------------------------------
/GoogleIOT/.gitignore:
--------------------------------------------------------------------------------
1 | db/*
2 | *.pem
3 | flash/config.py
4 |
--------------------------------------------------------------------------------
/GoogleIOT/README.md:
--------------------------------------------------------------------------------
1 |

2 |
3 | # Google Cloud Iot Core MQTT connection library
4 |
5 | ### requirement
6 |
7 | Pycom Firmware >= 1.20.0.rc11
8 |
9 | You will need to setup a Google IoT core registry as described here: https://cloud.google.com/iot/docs/quickstart#create_a_device_registry
10 |
11 | During the activation please collect the following informations: 'project_id',
12 | 'cloud_region' and 'registry_id'.
13 |
14 | ### usage
15 |
16 | - create a device registry:
17 | https://cloud.google.com/iot/docs/quickstart#create_a_device_registry
18 | - generate a key using the provided tool genkey.sh and add it to the platform
19 | - add the public key to Google IoT Core :
20 | https://cloud.google.com/iot/docs/quickstart#add_a_device_to_the_registry
21 | - copy config.example.py to config.py and edit the variable
22 | - upload the project using pymakr
23 |
--------------------------------------------------------------------------------
/GoogleIOT/flash/cert/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/GoogleIOT/flash/cert/.gitkeep
--------------------------------------------------------------------------------
/GoogleIOT/flash/config.example.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | ''' Set here you setup config in this example
12 | '''
13 | CONFIG = {
14 | 'wifi_ssid': "somewifi",
15 | 'wifi_password': 'iforgot',
16 | 'ntp_server': 'time.google.com',
17 | 'project_id': 'pybytes-101', # replace with your Google project_id
18 | 'cloud_region': 'us-central1', # replace
19 | 'registry_id': 'goinvent', # replace with your Google registry_id
20 | 'topic': '/devices/pysense2/events', # replace so match your device
21 | 'device_id': 'pysense2' #
22 | }
23 |
--------------------------------------------------------------------------------
/GoogleIOT/flash/google_iot_core.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | ''' A MQTT wrapper for Google Cloud IoT MQTT bridge
12 | Extended from umqtt.robust by Paul Sokolovsky with wrap of Google credentials
13 |
14 | https://github.com/micropython/micropython-lib/tree/master/umqtt.robust
15 | https://github.com/micropython/micropython-lib/tree/master/umqtt.simple
16 |
17 | Quick API Reference:
18 | connect(...) - Connect to a server. Returns True if this connection uses
19 | persistent session stored on a server (this will be always
20 | False if clean_session=True argument is used (default)).
21 | disconnect() - Disconnect from a server, release resources.
22 | ping() - Ping server (response is processed automatically by wait_msg()).
23 | publish() - Publish a message.
24 | subscribe() - Subscribe to a topic.
25 | set_callback() - Set callback for received subscription messages.
26 | wait_msg() - Wait for a server message. A subscription message will be
27 | delivered to a callback set with set_callback(), any other
28 | messages will be processed internally.
29 | check_msg() - Check if there's pending message from server. If yes, process
30 | the same way as wait_msg(), if not, return immediately.
31 | '''
32 |
33 | import json
34 | from binascii import b2a_base64
35 | from binascii import a2b_base64
36 | import ucrypto
37 | import utime
38 | import umqtt
39 |
40 | def _create_unsigned_jwt(project_id, expires=60 * 60 * 24):
41 | header = {
42 | 'alg': "RS256",
43 | 'typ': 'JWT'
44 | }
45 | token = {
46 | 'iat': utime.time(),
47 | 'exp': utime.time() + expires,
48 | 'aud': project_id
49 | }
50 | return b2a_base64(json.dumps(header)) + "." + \
51 | b2a_base64(json.dumps(token))
52 |
53 | def _get_google_client_id(
54 | project_id,
55 | cloud_region,
56 | registry_id,
57 | device_id):
58 | return "projects/%s/locations/%s/registries/%s/devices/%s" % (
59 | project_id, cloud_region, registry_id, device_id)
60 |
61 | def _create_google_jwt(project_id, private_key):
62 | to_sign = _create_unsigned_jwt(project_id)
63 | signed = ucrypto.generate_rsa_signature(to_sign, private_key)
64 | return to_sign + b'.' + b2a_base64(signed)
65 |
66 |
67 | class GoogleMQTTClient(umqtt.MQTTClient):
68 | ''' Instanciate a mqtt client
69 | Args:
70 | var_int (int): An integer.
71 | var_str (str): A string.
72 | project_id (str): your google's project_id
73 | private_key (bytes): private key bytes in pk8s format
74 | cloud_region (str): your google's region
75 | registry_id (str): the name you had given to your registry
76 | device_id: (str): the human friendly device name
77 | '''
78 |
79 | DELAY = 2
80 | DEBUG = True
81 | GOOGLE_CA = '/flash/cert/google_roots.pem'
82 | GOOGLE_MQTT = 'mqtt.googleapis.com'
83 |
84 | def __init__(
85 | self,
86 | project_id,
87 | private_key,
88 | cloud_region,
89 | registry_id,
90 | device_id):
91 | self.private_key = private_key
92 | self.project_id = project_id
93 | self.jwt = _create_google_jwt(self.project_id, self.private_key)
94 | google_client_id = _get_google_client_id(
95 | project_id, cloud_region, registry_id, device_id)
96 | google_args = self._get_google_mqtt_args(self.jwt)
97 | super().__init__(google_client_id, self.GOOGLE_MQTT, **google_args)
98 |
99 | def delay(self, i):
100 | utime.sleep(self.DELAY + i)
101 |
102 | def log(self, in_reconnect, err):
103 | if self.DEBUG:
104 | if in_reconnect:
105 | print("mqtt reconnect: %r" % err)
106 | else:
107 | print("mqtt: %r" % err)
108 |
109 | def reconnect(self):
110 | i = 0
111 | while True:
112 | if not self.is_jwt_valid():
113 | self.pswd = self.jwt = _create_google_jwt(
114 | self.project_id, self.private_key)
115 | try:
116 | return super().connect(False)
117 | except OSError as exception:
118 | self.log(True, exception)
119 | i += 1
120 | self.delay(i)
121 |
122 | def publish(self, topic, msg, retain=False, qos=0):
123 | if qos == 2:
124 | raise Exception("qos=2 not supported by mqtt bridge")
125 |
126 | while True:
127 | try:
128 | return super().publish(topic, msg, retain, qos)
129 | except OSError as exception:
130 | self.log(False, exception)
131 | self.reconnect()
132 |
133 | def wait_msg(self):
134 | while True:
135 | try:
136 | return super().wait_msg()
137 | except OSError as exception:
138 | self.log(False, exception)
139 | self.reconnect()
140 |
141 | def _get_google_mqtt_args(self, jwt):
142 | arguments = {
143 | 'user': '',
144 | 'password': jwt,
145 | 'port': 8883,
146 | 'ssl': True,
147 | 'ssl_params': {
148 | 'ca_certs': self.GOOGLE_CA
149 | }
150 | }
151 | return arguments
152 |
153 | def is_jwt_valid(self):
154 | try:
155 | token = json.loads(a2b_base64(self.jwt.decode().split('.')[1]))
156 | except Exception:
157 | return False
158 | return utime.time() - token.get('iat') < 60 * 60 * 24
159 |
160 | def set_last_will(self, topic, msg, retain=False, qos=0):
161 | raise Exception("set_last_will not supported by mqtt bridge")
162 |
--------------------------------------------------------------------------------
/GoogleIOT/flash/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | ''' Example Google IoT Core connection
12 | '''
13 | import utime
14 | import machine
15 | import _thread
16 | from network import WLAN
17 | from google_iot_core import GoogleMQTTClient
18 | from config import CONFIG
19 |
20 | # Connect to Wifi
21 | WLAN_I = WLAN(mode=WLAN.STA, max_tx_pwr=78)
22 | print('Connecting to WiFi %s' % CONFIG.get('wifi_ssid'))
23 | WLAN_I.connect(CONFIG.get('wifi_ssid'), (WLAN.WPA2, CONFIG.get('wifi_password')), timeout=60000)
24 | i = 0
25 | while not WLAN_I.isconnected():
26 | i = i + 1
27 | # print(".", end="")
28 | utime.sleep(1)
29 | if i > 60:
30 | print("\nWifi not available")
31 | break
32 |
33 | # Syncing time
34 | RTCI = machine.RTC()
35 | print('Syncing time with %s' % CONFIG.get('ntp_server'), end='')
36 | RTCI.ntp_sync(CONFIG.get('ntp_server'))
37 | while not RTCI.synced():
38 | print('.', end='')
39 | utime.sleep(1)
40 | print('')
41 |
42 | # read the private key
43 | FILE_HANDLE = open("cert/%s-pk8.key" % CONFIG.get('device_id'))
44 | PRIVATE_KEY = FILE_HANDLE.read()
45 | FILE_HANDLE.close()
46 |
47 | # make a mqtt client, connect and publish an empty message
48 | MQTT_CLIENT = GoogleMQTTClient(CONFIG.get('project_id'),
49 | PRIVATE_KEY,
50 | CONFIG.get('cloud_region'),
51 | CONFIG.get('registry_id'),
52 | CONFIG.get('device_id'))
53 |
54 |
55 | MQTT_CLIENT.connect()
56 | MQTT_CLIENT.publish(CONFIG.get('topic'), b'test')
57 |
58 | # make a demo callback
59 | def _sub_cb(topic, msg):
60 | ''' handle your message received here ...
61 | '''
62 | print('received:', topic, msg)
63 |
64 | # register callback
65 | MQTT_CLIENT.set_callback(_sub_cb)
66 |
67 | # example subscription
68 | MQTT_CLIENT.subscribe('/devices/%s/config' % CONFIG.get('device_id'), qos=1)
69 | while True:
70 | # Non-blocking wait for message
71 | MQTT_CLIENT.check_msg()
72 | # Then need to sleep to avoid 100% CPU usage (in a real
73 | # app other useful actions would be performed instead)
74 | utime.sleep_ms(100)
75 |
--------------------------------------------------------------------------------
/GoogleIOT/genkey.sh:
--------------------------------------------------------------------------------
1 | # Google Cloud IoT Core
2 | if [[ $# -eq 0 ]] ; then
3 | echo "Usage: $0 device_id"
4 | exit 0
5 | fi
6 |
7 | DB_DIR='db'
8 | DEVICE_ID=$1
9 |
10 | if [ ! -f $DB_DIR/$DEVICE_ID-priv.pem ]; then
11 | openssl genrsa -out $DB_DIR/$DEVICE_ID-priv.pem 2048
12 | fi
13 |
14 | if [ ! -f $DB_DIR/$DEVICE_ID-pub.pem ]; then
15 | openssl rsa -in $DB_DIR/$DEVICE_ID-priv.pem -pubout -out $DB_DIR/$DEVICE_ID-pub.pem
16 | fi
17 |
18 | if [ ! -f flash/cert/$DEVICE_ID-pk8.key ]; then
19 | openssl pkcs8 -topk8 -nocrypt -in $DB_DIR/$DEVICE_ID-priv.pem -out flash/cert/$DEVICE_ID-pk8.key
20 | fi
21 |
22 | if [ ! -f flash/cert/google_roots.pem ]; then
23 | wget "https://pki.google.com/roots.pem" -O flash/cert/google_roots.pem
24 | fi
25 |
26 | echo "Please add this public key to Google Cloud IoT Core Registry"
27 | cat $DB_DIR/$DEVICE_ID-pub.pem
28 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | release: pyscan pysense pysense2 pytrack pytrack2
2 |
3 |
4 | pyscan:
5 | rm -rf pyscan
6 | rm -f pyscan.zip
7 | @echo "Making Pyscan"
8 | mkdir pyscan
9 | mkdir pyscan/lib
10 | #sensors
11 | cp shields/lib/LIS2HH12.py pyscan/lib/
12 | cp shields/lib/MFRC630.py pyscan/lib/
13 | cp shields/lib/SI7006A20.py pyscan/lib/
14 | cp shields/lib/LTR329ALS01.py pyscan/lib/
15 | #pycoproc
16 | cp shields/lib/pycoproc_1.py pyscan/lib/
17 | #example
18 | cp shields/pyscan_1.py pyscan/main.py
19 |
20 | zip -r pyscan.zip pyscan
21 |
22 | pysense:
23 | rm -rf pysense
24 | rm -f pysense.zip
25 | @echo "Making Pysense"
26 | mkdir pysense
27 | mkdir pysense/lib
28 | # sensors
29 | cp shields/lib/LIS2HH12.py pysense/lib/
30 | cp shields/lib/LTR329ALS01.py pysense/lib/
31 | cp shields/lib/MPL3115A2.py pysense/lib/
32 | cp shields/lib/SI7006A20.py pysense/lib/
33 | # pycoproc
34 | cp shields/lib/pycoproc_1.py pysense/lib/
35 | # example
36 | cp shields/pysense_1.py pysense/main.py
37 |
38 | zip -r pysense.zip pysense
39 |
40 | pysense2:
41 | rm -rf pysense2
42 | rm -f pysense2.zip
43 | @echo "Making Pysense 2"
44 | mkdir pysense2
45 | mkdir pysense2/lib
46 | # sensors
47 | cp shields/lib/LIS2HH12.py pysense2/lib/
48 | cp shields/lib/LTR329ALS01.py pysense2/lib/
49 | cp shields/lib/MPL3115A2.py pysense2/lib/
50 | cp shields/lib/SI7006A20.py pysense2/lib/
51 | # pycoproc
52 | cp shields/lib/pycoproc_2.py pysense2/lib/
53 | # example
54 | cp shields/pysense_2.py pysense2/main.py
55 |
56 | zip -r pysense2.zip pysense2
57 |
58 | pytrack:
59 | rm -rf pytrack
60 | rm -f pytrack.zip
61 | @echo "Making Pytrack"
62 | mkdir pytrack
63 | mkdir pytrack/lib
64 | #sensors
65 | cp shields/lib/L76GNSS.py pytrack/lib/
66 | cp shields/lib/LIS2HH12.py pytrack/lib/
67 | #pycoproc
68 | cp shields/lib/pycoproc_1.py pytrack/lib/
69 | #example
70 | cp shields/pytrack_1.py pytrack/main.py
71 |
72 | zip -r pytrack.zip pytrack
73 |
74 | pytrack2:
75 | rm -rf pytrack2
76 | rm -f pytrack2.zip
77 | @echo "Making Pytrack2"
78 | mkdir pytrack2
79 | mkdir pytrack2/lib
80 | #sensors
81 | cp shields/lib/L76GNSS.py pytrack2/lib/
82 | cp shields/lib/LIS2HH12.py pytrack2/lib/
83 | #pycoproc
84 | cp shields/lib/pycoproc_2.py pytrack2/lib/
85 | #example
86 | cp shields/pytrack_2.py pytrack2/main.py
87 |
88 | zip -r pytrack2.zip pytrack2
89 |
90 | clean:
91 | @echo "Cleaning up files"
92 | rm -rf pyscan
93 | rm -rf pysense
94 | rm -rf pysense2
95 | rm -rf pytrack
96 | rm -rf pytrack2
97 |
98 | rm -f pyscan.zip
99 | rm -f pysense.zip
100 | rm -f pysense2.zip
101 | rm -f pytrack.zip
102 | rm -f pytrack2.zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Pycom Libraries and Examples
4 |
5 | ## Introduction
6 | This repository contains libraries and out of the box examples for Pycom devices, including the Shields: Pysense, Pytrack, and Pyscan.
7 |
8 | ## Table of Contents
9 | * [Examples](/examples)
10 | * [Libraries](/lib)
11 | * [Shields](/shields)
12 |
13 | ## Links
14 | * [Pycom](https://pycom.io)
15 | * [Forum](https://forum.pycom.io)
16 | * [Docs](https://docs.pycom.io)
17 |
--------------------------------------------------------------------------------
/examples/DS18X20/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/DS18X20/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import time
12 | from machine import Pin
13 | from onewire import DS18X20
14 | from onewire import OneWire
15 |
16 | #DS18B20 data line connected to pin P10
17 | ow = OneWire(Pin('P10'))
18 | temp = DS18X20(ow)
19 |
20 | while True:
21 | temp.start_conversion()
22 | time.sleep(1)
23 | print(temp.read_temp_async())
24 | time.sleep(1)
25 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/README.md:
--------------------------------------------------------------------------------
1 | Coming soon
2 |
3 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | #LORASERVER configuration
12 | LORASERVER_IP = "127.0.0.1"
13 | LORASERVER_URL = 'http://localhost'
14 | LORASERVER_MQTT_PORT = 1883
15 | LORASERVER_API_PORT = 8080
16 | LORASERVER_EMAIL = 'admin'
17 | LORASERVER_PASS = 'admin'
18 |
19 | LORASERVER_SERVICE_PROFILE = 'ota_sp'
20 | LORASERVER_DOWNLINK_DR = 5
21 | LORASERVER_DOWNLINK_FREQ = 869525000
22 | LORASERVER_APP_ID = 1 # Read from Web Interface / Applications
23 |
24 | #update configuration
25 | UPDATE_DELAY = 300
26 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/firmware/1.17.0/flash/OTA_INFO.py:
--------------------------------------------------------------------------------
1 | 1.17.0
2 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/firmware/1.17.0/flash/loranet.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import socket
13 | import binascii
14 | import struct
15 | import time
16 | import _thread
17 |
18 | class LoraNet:
19 | def __init__(self, frequency, dr, region, device_class=LoRa.CLASS_C, activation = LoRa.OTAA, auth = None):
20 | self.frequency = frequency
21 | self.dr = dr
22 | self.region = region
23 | self.device_class = device_class
24 | self.activation = activation
25 | self.auth = auth
26 | self.sock = None
27 | self._exit = False
28 | self.s_lock = _thread.allocate_lock()
29 | self.lora = LoRa(mode=LoRa.LORAWAN, region = self.region, device_class = self.device_class)
30 |
31 | self._msg_queue = []
32 | self.q_lock = _thread.allocate_lock()
33 | self._process_ota_msg = None
34 |
35 | def stop(self):
36 | self._exit = True
37 |
38 | def init(self, process_msg_callback):
39 | self._process_ota_msg = process_msg_callback
40 |
41 | def receive_callback(self, lora):
42 | events = lora.events()
43 | if events & LoRa.RX_PACKET_EVENT:
44 | rx, port = self.sock.recvfrom(256)
45 | if rx:
46 | if '$OTA' in rx:
47 | print("OTA msg received: {}".format(rx))
48 | self._process_ota_msg(rx.decode())
49 | else:
50 | self.q_lock.acquire()
51 | self._msg_queue.append(rx)
52 | self.q_lock.release()
53 |
54 | def connect(self):
55 | if self.activation != LoRa.OTAA and self.activation != LoRa.ABP:
56 | raise ValueError("Invalid Lora activation method")
57 | if len(self.auth) < 3:
58 | raise ValueError("Invalid authentication parameters")
59 |
60 | self.lora.callback(trigger=LoRa.RX_PACKET_EVENT, handler=self.receive_callback)
61 |
62 | # set the 3 default channels to the same frequency
63 | self.lora.add_channel(0, frequency=self.frequency, dr_min=0, dr_max=5)
64 | self.lora.add_channel(1, frequency=self.frequency, dr_min=0, dr_max=5)
65 | self.lora.add_channel(2, frequency=self.frequency, dr_min=0, dr_max=5)
66 |
67 | # remove all the non-default channels
68 | for i in range(3, 16):
69 | self.lora.remove_channel(i)
70 |
71 | # authenticate with abp or ota
72 | if self.activation == LoRa.OTAA:
73 | self._authenticate_otaa(self.auth)
74 | else:
75 | self._authenticate_abp(self.auth)
76 |
77 | # create socket to server
78 | self._create_socket()
79 |
80 | def _authenticate_otaa(self, auth_params):
81 |
82 | # create an OTAA authentication params
83 | self.dev_eui = binascii.unhexlify(auth_params[0])
84 | self.app_eui = binascii.unhexlify(auth_params[1])
85 | self.app_key = binascii.unhexlify(auth_params[2])
86 |
87 | self.lora.join(activation=LoRa.OTAA, auth=(self.dev_eui, self.app_eui, self.app_key), timeout=0, dr=self.dr)
88 |
89 | while not self.lora.has_joined():
90 | time.sleep(2.5)
91 | print('Not joined yet...')
92 |
93 | def has_joined(self):
94 | return self.lora.has_joined()
95 |
96 | def _authenticate_abp(self, auth_params):
97 | # create an ABP authentication params
98 | self.dev_addr = struct.unpack(">l", binascii.unhexlify(auth_params[0]))[0]
99 | self.nwk_swkey = binascii.unhexlify(auth_params[1])
100 | self.app_swkey = binascii.unhexlify(auth_params[2])
101 |
102 | self.lora.join(activation=LoRa.ABP, auth=(self.dev_addr, self.nwk_swkey, self.app_swkey))
103 |
104 | def _create_socket(self):
105 |
106 | # create a LoRa socket
107 | self.sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
108 |
109 | # set the LoRaWAN data rate
110 | self.sock.setsockopt(socket.SOL_LORA, socket.SO_DR, self.dr)
111 |
112 | # make the socket non blocking
113 | self.sock.setblocking(False)
114 |
115 | time.sleep(2)
116 |
117 | def send(self, packet):
118 | with self.s_lock:
119 | self.sock.send(packet)
120 |
121 | def receive(self, bufsize):
122 | with self.q_lock:
123 | if len(self._msg_queue) > 0:
124 | return self._msg_queue.pop(0)
125 | return ''
126 |
127 | def get_dev_eui(self):
128 | return binascii.hexlify(self.lora.mac()).decode('ascii')
129 |
130 | def change_to_multicast_mode(self, mcAuth):
131 | print('Start listening for firmware updates ...........')
132 |
133 | if self.device_class != LoRa.CLASS_C:
134 | self.lora = LoRa(mode=LoRa.LORAWAN, region = self.region, device_class=LoRa.CLASS_C)
135 | self.connect()
136 |
137 | mcAddr = struct.unpack(">l", binascii.unhexlify(mcAuth[0]))[0]
138 | mcNwkKey = binascii.unhexlify(mcAuth[1])
139 | mcAppKey = binascii.unhexlify(mcAuth[2])
140 |
141 | self.lora.join_multicast_group(mcAddr, mcNwkKey, mcAppKey)
142 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/firmware/1.17.0/flash/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from loranet import LoraNet
12 | from ota import LoraOTA
13 | from network import LoRa
14 | import machine
15 | import utime
16 |
17 | def main():
18 | LORA_FREQUENCY = 868100000
19 | LORA_NODE_DR = 5
20 | LORA_REGION = LoRa.EU868
21 | LORA_DEVICE_CLASS = LoRa.CLASS_C
22 | LORA_ACTIVATION = LoRa.OTAA
23 | LORA_CRED = ('240ac4fffe0bf998', '948c87eff87f04508f64661220f71e3f', '5e6795a5c9abba017d05a2ffef6ba858')
24 |
25 | lora = LoraNet(LORA_FREQUENCY, LORA_NODE_DR, LORA_REGION, LORA_DEVICE_CLASS, LORA_ACTIVATION, LORA_CRED)
26 | lora.connect()
27 |
28 | ota = LoraOTA(lora)
29 |
30 | while True:
31 | rx = lora.receive(256)
32 | if rx:
33 | print('Received user message: {}'.format(rx))
34 |
35 | utime.sleep(2)
36 |
37 | main()
38 |
39 | #try:
40 | # main()
41 | #except Exception as e:
42 | # print('Firmware exception: Reverting to old firmware')
43 | # LoraOTA.revert()
44 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/firmware/1.17.0/flash/watchdog.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import Timer
12 | import _thread
13 |
14 | class Watchdog:
15 |
16 | def __init__(self):
17 | self.failed = False
18 | self.acknowledged = 0
19 | self._alarm = None
20 | self._lock = _thread.allocate_lock()
21 |
22 | def enable(self, timeout = 120):
23 | if self._alarm:
24 | self._alarm.cancel()
25 | self._alarm = None
26 |
27 | self._alarm = Timer.Alarm(self._check, s = timeout, periodic = True)
28 |
29 | def _check(self, alarm):
30 | with self._lock:
31 | if self.acknowledged > 0:
32 | self.failed = False
33 | self.acknowledged = 0
34 | else:
35 | self.failed = True
36 |
37 | def ack(self):
38 | with self._lock:
39 | self.acknowledged += 1
40 |
41 | def update_failed(self):
42 | with self._lock:
43 | return self.failed
44 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/firmware/1.17.1/flash/OTA_INFO.py:
--------------------------------------------------------------------------------
1 | 1.17.1
2 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/firmware/1.17.1/flash/loranet.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import socket
13 | import binascii
14 | import struct
15 | import time
16 | import _thread
17 |
18 | class LoraNet:
19 | def __init__(self, frequency, dr, region, device_class=LoRa.CLASS_C, activation = LoRa.OTAA, auth = None):
20 | self.frequency = frequency
21 | self.dr = dr
22 | self.region = region
23 | self.device_class = device_class
24 | self.activation = activation
25 | self.auth = auth
26 | self.sock = None
27 | self._exit = False
28 | self.s_lock = _thread.allocate_lock()
29 | self.lora = LoRa(mode=LoRa.LORAWAN, region = self.region, device_class = self.device_class)
30 |
31 | self._msg_queue = []
32 | self.q_lock = _thread.allocate_lock()
33 | self._process_ota_msg = None
34 |
35 | def stop(self):
36 | self._exit = True
37 |
38 | def init(self, process_msg_callback):
39 | self._process_ota_msg = process_msg_callback
40 |
41 | def receive_callback(self, lora):
42 | events = lora.events()
43 | if events & LoRa.RX_PACKET_EVENT:
44 | rx, port = self.sock.recvfrom(256)
45 | if rx:
46 | if '$OTA' in rx:
47 | print("OTA msg received: {}".format(rx))
48 | self._process_ota_msg(rx.decode())
49 | else:
50 | self.q_lock.acquire()
51 | self._msg_queue.append(rx)
52 | self.q_lock.release()
53 |
54 | def connect(self):
55 | if self.activation != LoRa.OTAA and self.activation != LoRa.ABP:
56 | raise ValueError("Invalid Lora activation method")
57 | if len(self.auth) < 3:
58 | raise ValueError("Invalid authentication parameters")
59 |
60 | self.lora.callback(trigger=LoRa.RX_PACKET_EVENT, handler=self.receive_callback)
61 |
62 | # set the 3 default channels to the same frequency
63 | self.lora.add_channel(0, frequency=self.frequency, dr_min=0, dr_max=5)
64 | self.lora.add_channel(1, frequency=self.frequency, dr_min=0, dr_max=5)
65 | self.lora.add_channel(2, frequency=self.frequency, dr_min=0, dr_max=5)
66 |
67 | # remove all the non-default channels
68 | for i in range(3, 16):
69 | self.lora.remove_channel(i)
70 |
71 | # authenticate with abp or ota
72 | if self.activation == LoRa.OTAA:
73 | self._authenticate_otaa(self.auth)
74 | else:
75 | self._authenticate_abp(self.auth)
76 |
77 | # create socket to server
78 | self._create_socket()
79 |
80 | def _authenticate_otaa(self, auth_params):
81 |
82 | # create an OTAA authentication params
83 | self.dev_eui = binascii.unhexlify(auth_params[0])
84 | self.app_eui = binascii.unhexlify(auth_params[1])
85 | self.app_key = binascii.unhexlify(auth_params[2])
86 |
87 | self.lora.join(activation=LoRa.OTAA, auth=(self.dev_eui, self.app_eui, self.app_key), timeout=0, dr=self.dr)
88 |
89 | while not self.lora.has_joined():
90 | time.sleep(2.5)
91 | print('Not joined yet...')
92 |
93 | def has_joined(self):
94 | return self.lora.has_joined()
95 |
96 | def _authenticate_abp(self, auth_params):
97 | # create an ABP authentication params
98 | self.dev_addr = struct.unpack(">l", binascii.unhexlify(auth_params[0]))[0]
99 | self.nwk_swkey = binascii.unhexlify(auth_params[1])
100 | self.app_swkey = binascii.unhexlify(auth_params[2])
101 |
102 | self.lora.join(activation=LoRa.ABP, auth=(self.dev_addr, self.nwk_swkey, self.app_swkey))
103 |
104 | def _create_socket(self):
105 |
106 | # create a LoRa socket
107 | self.sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
108 |
109 | # set the LoRaWAN data rate
110 | self.sock.setsockopt(socket.SOL_LORA, socket.SO_DR, self.dr)
111 |
112 | # make the socket non blocking
113 | self.sock.setblocking(False)
114 |
115 | time.sleep(2)
116 |
117 | def send(self, packet):
118 | with self.s_lock:
119 | self.sock.send(packet)
120 |
121 | def receive(self, bufsize):
122 | with self.q_lock:
123 | if len(self._msg_queue) > 0:
124 | return self._msg_queue.pop(0)
125 | return ''
126 |
127 | def get_dev_eui(self):
128 | return binascii.hexlify(self.lora.mac()).decode('ascii')
129 |
130 | def change_to_multicast_mode(self, mcAuth):
131 | print('Start listening for firmware updates ...........')
132 |
133 | if self.device_class != LoRa.CLASS_C:
134 | self.lora = LoRa(mode=LoRa.LORAWAN, region = self.region, device_class=LoRa.CLASS_C)
135 | self.connect()
136 |
137 | mcAddr = struct.unpack(">l", binascii.unhexlify(mcAuth[0]))[0]
138 | mcNwkKey = binascii.unhexlify(mcAuth[1])
139 | mcAppKey = binascii.unhexlify(mcAuth[2])
140 |
141 | self.lora.join_multicast_group(mcAddr, mcNwkKey, mcAppKey)
142 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/firmware/1.17.1/flash/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from loranet import LoraNet
12 | from ota import LoraOTA
13 | from network import LoRa
14 | import machine
15 | import utime
16 |
17 | def main():
18 | print('Booting with firmware version 1.17.1')
19 |
20 | LORA_FREQUENCY = 868100000
21 | LORA_NODE_DR = 5
22 | LORA_REGION = LoRa.EU868
23 | LORA_DEVICE_CLASS = LoRa.CLASS_C
24 | LORA_ACTIVATION = LoRa.OTAA
25 | LORA_CRED = ('240ac4fffe0bf998', '948c87eff87f04508f64661220f71e3f', '5e6795a5c9abba017d05a2ffef6ba858')
26 |
27 | lora = LoraNet(LORA_FREQUENCY, LORA_NODE_DR, LORA_REGION, LORA_DEVICE_CLASS, LORA_ACTIVATION, LORA_CRED)
28 | lora.connect()
29 |
30 | ota = LoraOTA(lora)
31 |
32 | while True:
33 | rx = lora.receive(256)
34 | if rx:
35 | print('Received user message: {}'.format(rx))
36 |
37 | utime.sleep(2)
38 |
39 | main()
40 |
41 | #try:
42 | # main()
43 | #except Exception as e:
44 | # print('Firmware exception: Reverting to old firmware')
45 | # LoraOTA.revert()
46 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/firmware/1.17.1/flash/watchdog.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import Timer
12 | import _thread
13 |
14 | class Watchdog:
15 |
16 | def __init__(self):
17 | self.failed = False
18 | self.acknowledged = 0
19 | self._alarm = None
20 | self._lock = _thread.allocate_lock()
21 |
22 | def enable(self, timeout = 120):
23 | if self._alarm:
24 | self._alarm.cancel()
25 | self._alarm = None
26 |
27 | self._alarm = Timer.Alarm(self._check, s = timeout, periodic = True)
28 |
29 | def _check(self, alarm):
30 | with self._lock:
31 | if self.acknowledged > 0:
32 | self.failed = False
33 | self.acknowledged = 0
34 | else:
35 | self.failed = True
36 |
37 | def ack(self):
38 | with self._lock:
39 | self.acknowledged += 1
40 |
41 | def update_failed(self):
42 | with self._lock:
43 | return self.failed
44 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/requirements.txt:
--------------------------------------------------------------------------------
1 | paho_mqtt==1.5.1
2 |
--------------------------------------------------------------------------------
/examples/OTA-lorawan/updaterService.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import paho.mqtt.client as paho
12 | from ota import OTAHandler
13 | import signal
14 | import time
15 | import config
16 | import sys
17 |
18 | exit = False
19 | client = None
20 |
21 | def sigint_handler(signum, frame):
22 | global exit
23 | exit = True
24 | print("Terminating Lora OTA updater")
25 |
26 | def on_message(mosq, ota, msg):
27 | print("{} {} {}".format(msg.topic, msg.qos, msg.payload))
28 | ota.process_rx_msg(msg.payload.decode())
29 |
30 | def on_publish(mosq, obj, mid):
31 | pass
32 |
33 | if __name__ == '__main__':
34 | signal.signal(signal.SIGINT, sigint_handler)
35 |
36 | ota = OTAHandler()
37 |
38 | client = paho.Client(userdata=ota)
39 | client.connect(config.LORASERVER_IP, config.LORASERVER_MQTT_PORT, 60)
40 |
41 | client.on_message = on_message
42 | client.on_publish = on_publish
43 |
44 | client.subscribe("application/+/device/+/event/up", 0)
45 |
46 | ota.set_mqtt_client(client)
47 |
48 | while client.loop() == 0 and not exit:
49 | pass
50 |
51 | ota.stop()
52 | sys.exit(0)
53 |
--------------------------------------------------------------------------------
/examples/OTA/1.0.0/flash/config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | WIFI_SSID = "ENTER_ME"
12 | WIFI_PW = "ENTER_ME"
13 | SERVER_IP = "ENTER_ME"
14 |
--------------------------------------------------------------------------------
/examples/OTA/1.0.0/flash/get_id.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import binascii
13 | lora = LoRa(mode=LoRa.LORAWAN)
14 | print(binascii.hexlify(lora.mac()).upper().decode('utf-8'))
15 |
--------------------------------------------------------------------------------
/examples/OTA/1.0.0/flash/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa, WLAN
12 | import socket
13 | import time
14 | from OTA import WiFiOTA
15 | from time import sleep
16 | import pycom
17 | import binascii
18 |
19 | from config import WIFI_SSID, WIFI_PW, SERVER_IP
20 |
21 | # Turn on GREEN LED
22 | pycom.heartbeat(False)
23 | pycom.rgbled(0xff00)
24 |
25 | # Setup OTA
26 | ota = WiFiOTA(WIFI_SSID,
27 | WIFI_PW,
28 | SERVER_IP, # Update server address
29 | 8000) # Update server port
30 |
31 | # Turn off WiFi to save power
32 | w = WLAN()
33 | w.deinit()
34 |
35 | # Initialize LoRa in LORAWAN mode.
36 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
37 |
38 | app_eui = binascii.unhexlify('ENTER_ME')
39 | app_key = binascii.unhexlify('ENTER_ME')
40 |
41 | # join a network using OTAA (Over the Air Activation)
42 | lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0)
43 |
44 | # wait until the module has joined the network
45 | while not lora.has_joined():
46 | time.sleep(2.5)
47 | print('Not yet joined...')
48 |
49 | # create a LoRa socket
50 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
51 |
52 | # set the LoRaWAN data rate
53 | s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)
54 |
55 | # make the socket blocking
56 | # (waits for the data to be sent and for the 2 receive windows to expire)
57 | s.setblocking(True)
58 |
59 | while True:
60 | # send some data
61 | s.send(bytes([0x04, 0x05, 0x06]))
62 |
63 | # make the socket non-blocking
64 | # (because if there's no data received it will block forever...)
65 | s.setblocking(False)
66 |
67 | # get any data received (if any...)
68 | data = s.recv(64)
69 |
70 | # Some sort of OTA trigger
71 | if data == bytes([0x01, 0x02, 0x03]):
72 | print("Performing OTA")
73 | # Perform OTA
74 | ota.connect()
75 | ota.update()
76 |
77 | sleep(5)
78 |
--------------------------------------------------------------------------------
/examples/OTA/1.0.1/flash/config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2018, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | WIFI_SSID = "ENTER_ME"
12 | WIFI_PW = "ENTER_ME"
13 | SERVER_IP = "ENTER_ME"
14 |
--------------------------------------------------------------------------------
/examples/OTA/1.0.1/flash/get_id.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2018, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import binascii
13 | lora = LoRa(mode=LoRa.LORAWAN)
14 | print(binascii.hexlify(lora.mac()).upper().decode('utf-8'))
15 |
--------------------------------------------------------------------------------
/examples/OTA/1.0.1/flash/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2018, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa, WLAN
12 | import socket
13 | import time
14 | from OTA import WiFiOTA
15 | from time import sleep
16 | import pycom
17 | import binascii
18 |
19 | from config import WIFI_SSID, WIFI_PW, SERVER_IP
20 |
21 | # Turn on GREEN LED
22 | pycom.heartbeat(False)
23 | pycom.rgbled(0xff)
24 |
25 | # Setup OTA
26 | ota = WiFiOTA(WIFI_SSID,
27 | WIFI_PW,
28 | SERVER_IP, # Update server address
29 | 8000) # Update server port
30 |
31 | # Turn off WiFi to save power
32 | w = WLAN()
33 | w.deinit()
34 |
35 | # Initialize LoRa in LORAWAN mode.
36 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
37 |
38 | app_eui = binascii.unhexlify('ENTER_ME')
39 | app_key = binascii.unhexlify('ENTER_ME')
40 |
41 | # join a network using OTAA (Over the Air Activation)
42 | lora.join(activation=LoRa.OTAA, auth=(app_eui, app_key), timeout=0)
43 |
44 | # wait until the module has joined the network
45 | while not lora.has_joined():
46 | time.sleep(2.5)
47 | print('Not yet joined...')
48 |
49 | # create a LoRa socket
50 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
51 |
52 | # set the LoRaWAN data rate
53 | s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)
54 |
55 | # make the socket blocking
56 | # (waits for the data to be sent and for the 2 receive windows to expire)
57 | s.setblocking(True)
58 |
59 | while True:
60 | # send some data
61 | s.send(bytes([0x04, 0x05, 0x06]))
62 |
63 | # make the socket non-blocking
64 | # (because if there's no data received it will block forever...)
65 | s.setblocking(False)
66 |
67 | # get any data received (if any...)
68 | data = s.recv(64)
69 |
70 | # Some sort of OTA trigger
71 | if data == bytes([0x01, 0x02, 0x03]):
72 | print("Performing OTA")
73 | # Perform OTA
74 | ota.connect()
75 | ota.update()
76 |
77 | sleep(5)
78 |
--------------------------------------------------------------------------------
/examples/OTA/README.md:
--------------------------------------------------------------------------------
1 | Overview
2 | --------
3 |
4 | This directory contains a example implementation of over the air (OTA)
5 | firmware updates. This consists of two components:
6 | - A server that serves the update files and generates update "manifests"
7 | - A library that allows a Pycom module perform updates from the server
8 |
9 | This directory is laid out such that the update sever can directly run from it.
10 | For a detailed description of how the server expect the directory to be structured please read the comment at the top of `OTA_server.py`.
11 |
12 | Setup
13 | -----
14 | To start the server simply run the `OTA_server.py` script using python 3. This
15 | will run a HTTP server on port 8000 (this can be changed in the code if
16 | necessary).
17 |
18 | In this project you will find two directories named `1.0.0` and `1.0.1`. These
19 | are both working examples of the OTA procedure, the only difference being the
20 | colour of the on-board LED so that a successful update can be demonstrated. You
21 | should upload version `1.0.0` to the module first and then via the OTA update
22 | procedure it will update to version `1.0.1`.
23 |
24 | In this example the OTA procedure is trigger via LoRaWAN downlink message. In
25 | order to use these examples you will need to enter your own `app_eui` and
26 | `app_key`. As well as this you will need to edit `config.py` to add your WiFi
27 | SSID, password and the address of the update server. Ensure you make these changes in both `1.0.0` and `1.0.1` or the code will stop working after the
28 | OTA update.
29 |
30 | The OTA library can be found in either `1.0.0\lib\OTA.py` or
31 | `1.0.1\lib\OTA.py`.
32 |
33 | For a detailed explanation of how the server works please look in
34 | `OTA_server.py`. The comment at the top of the file explains how it works in
35 | detail.
36 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | ## Overview
2 | This folder contains several samples that demonstrate various Pycom board functions. The samples are currently provided with the boot.py file to copy directly on the board.
3 |
4 | ## Installation
5 |
6 | This section explains the individual steps to run example application using the Pymakr.
7 | Steps:
8 | - Open Pymakr
9 | - In the menu, go to Project > New
10 | - Fill project name, select example folder for Project directory and select project type "Python project"
11 | - On popup add existing files to the project.
12 |
--------------------------------------------------------------------------------
/examples/accelerometer_wake/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from pytrack import Pytrack
12 | #from pysense import Pysense
13 | from LIS2HH12 import LIS2HH12
14 | import pycom
15 | import time
16 |
17 | pycom.heartbeat(False)
18 |
19 | py = Pytrack()
20 | # py = Pysense()
21 |
22 | # display the reset reason code and the sleep remaining in seconds
23 | # possible values of wakeup reason are:
24 | # WAKE_REASON_ACCELEROMETER = 1
25 | # WAKE_REASON_PUSH_BUTTON = 2
26 | # WAKE_REASON_TIMER = 4
27 | # WAKE_REASON_INT_PIN = 8
28 | print("Wakeup reason: " + str(py.get_wake_reason()) + "; Aproximate sleep remaining: " + str(py.get_sleep_remaining()) + " sec")
29 | time.sleep(0.5)
30 |
31 | # enable wakeup source from INT pin
32 | py.setup_int_pin_wake_up(False)
33 |
34 | # enable activity and also inactivity interrupts, using the default callback handler
35 | py.setup_int_wake_up(True, True)
36 |
37 | acc = LIS2HH12()
38 | # enable the activity/inactivity interrupts
39 | # set the accelereation threshold to 2000mG (2G) and the min duration to 200ms
40 | acc.enable_activity_interrupt(2000, 200)
41 |
42 | # check if we were awaken due to activity
43 | if acc.activity():
44 | pycom.rgbled(0xFF0000)
45 | else:
46 | pycom.rgbled(0x00FF00) # timer wake-up
47 | time.sleep(0.1)
48 |
49 | # go to sleep for 5 minutes maximum if no accelerometer interrupt happens
50 | py.setup_sleep(300)
51 | py.go_to_sleep()
52 |
--------------------------------------------------------------------------------
/examples/adc/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/adc/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import ADC
12 | import time
13 |
14 | adc = ADC(0)
15 | adc_c = adc.channel(pin='P13')
16 |
17 | while True:
18 | value = adc_c.value()
19 | print("ADC value:" + str(value))
20 | time.sleep(1)
21 |
--------------------------------------------------------------------------------
/examples/bluetooth/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/bluetooth/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import Bluetooth
12 | import binascii
13 | import time
14 | bt = Bluetooth()
15 | bt.start_scan(-1)
16 |
17 | while True:
18 | adv = bt.get_adv()
19 | if adv:
20 | # try to get the complete name
21 | print(bt.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL))
22 |
23 | # try to get the manufacturer data (Apple's iBeacon data is sent here)
24 | mfg_data = bt.resolve_adv_data(adv.data, Bluetooth.ADV_MANUFACTURER_DATA)
25 |
26 | if mfg_data:
27 | # try to get the manufacturer data (Apple's iBeacon data is sent here)
28 | print(binascii.hexlify(mfg_data))
29 |
30 | if bt.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL) == 'Heart Rate':
31 | conn = bt.connect(adv.mac)
32 | services = conn.services()
33 | for service in services:
34 | time.sleep(0.050)
35 | if type(service.uuid()) == bytes:
36 | print('Reading chars from service = {}'.format(service.uuid()))
37 | else:
38 | print('Reading chars from service = %x' % service.uuid())
39 | chars = service.characteristics()
40 | for char in chars:
41 | if (char.properties() & Bluetooth.PROP_READ):
42 | print('char {} value = {}'.format(char.uuid(), char.read()))
43 | conn.disconnect()
44 | break
45 | else:
46 | time.sleep(0.050)
47 |
--------------------------------------------------------------------------------
/examples/deepsleep/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from deepsleep import DeepSleep
12 | import deepsleep
13 |
14 | ds = DeepSleep()
15 |
16 | # get the wake reason and the value of the pins during wake up
17 | wake_s = ds.get_wake_status()
18 | print(wake_s)
19 |
20 | if wake_s['wake'] == deepsleep.PIN_WAKE:
21 | print("Pin wake up")
22 | elif wake_s['wake'] == deepsleep.TIMER_WAKE:
23 | print("Timer wake up")
24 | else: # deepsleep.POWER_ON_WAKE:
25 | print("Power ON reset")
26 |
27 | ds.enable_pullups('P17') # can also do ds.enable_pullups(['P17', 'P18'])
28 | ds.enable_wake_on_fall('P17') # can also do ds.enable_wake_on_fall(['P17', 'P18'])
29 |
30 | ds.go_to_sleep(60) # go to sleep for 60 seconds
31 |
--------------------------------------------------------------------------------
/examples/https/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/https/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import socket
12 | import ssl
13 |
14 | # Connect without a certificate
15 | s = socket()
16 | ss = ssl.wrap_socket(s)
17 | ss.connect(socket.getaddrinfo('www.google.com', 443)[0][-1])
18 |
19 | # Connect with a certificate
20 | s = socket.socket()
21 | ss = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ca_certs='/flash/cert/ca.pem')
22 | ss.connect(socket.getaddrinfo('cloud.blynk.cc', 8441)[0][-1])
--------------------------------------------------------------------------------
/examples/i2c/bh1750fvi.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | # Simple driver for the BH1750FVI digital light sensor
12 |
13 | class BH1750FVI:
14 | MEASUREMENT_TIME = const(120)
15 |
16 | def __init__(self, i2c, addr=0x23, period=150):
17 | self.i2c = i2c
18 | self.period = period
19 | self.addr = addr
20 | self.time = 0
21 | self.value = 0
22 | self.i2c.writeto(addr, bytes([0x10])) # start continuos 1 Lux readings every 120ms
23 |
24 | def read(self):
25 | self.time += self.period
26 | if self.time >= MEASUREMENT_TIME:
27 | self.time = 0
28 | data = self.i2c.readfrom(self.addr, 2)
29 | self.value = (((data[0] << 8) + data[1]) * 1200) // 1000
30 | return self.value
--------------------------------------------------------------------------------
/examples/i2c/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/i2c/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import socket
12 | import time
13 | import pycom
14 | import struct
15 | from network import LoRa
16 | from machine import I2C
17 | import bh1750fvi
18 |
19 | LORA_PKG_FORMAT = "!BH"
20 | LORA_CONFIRM_FORMAT = "!BB"
21 |
22 | DEVICE_ID = 1
23 |
24 | pycom.heartbeat(False)
25 |
26 | lora = LoRa(mode=LoRa.LORA, tx_iq=True, frequency = 863000000)
27 | lora_sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
28 | lora_sock.setblocking(False)
29 |
30 | i2c = I2C(0, I2C.MASTER, baudrate=100000)
31 | light_sensor = bh1750fvi.BH1750FVI(i2c, addr=i2c.scan()[0])
32 |
33 | while(True):
34 | msg = struct.pack(LORA_PKG_FORMAT, DEVICE_ID, light_sensor.read())
35 | lora_sock.send(msg)
36 |
37 | pycom.rgbled(0x150000)
38 |
39 | wait = 5
40 | while (wait > 0):
41 | wait = wait - 0.1
42 | time.sleep(0.1)
43 | recv_data = lora_sock.recv(64)
44 |
45 | if (len (recv_data) >= 2):
46 | status, device_id = struct.unpack(LORA_CONFIRM_FORMAT, recv_data)
47 |
48 | if (device_id == DEVICE_ID and status == 200):
49 | pycom.rgbled(0x001500)
50 | wait = 0
51 |
52 | time.sleep(1)
--------------------------------------------------------------------------------
/examples/lopy-lopy/lopy-A/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/lopy-lopy/lopy-A/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import socket
13 | import time
14 |
15 | lora = LoRa(mode=LoRa.LORA, frequency=863000000)
16 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
17 | s.setblocking(False)
18 |
19 | while True:
20 | if s.recv(64) == b'Ping':
21 | s.send('Pong')
22 | time.sleep(5)
23 |
--------------------------------------------------------------------------------
/examples/lopy-lopy/lopy-B/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/lopy-lopy/lopy-B/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import socket
13 | import time
14 |
15 | lora = LoRa(mode=LoRa.LORA, frequency=863000000)
16 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
17 | s.setblocking(False)
18 |
19 | while True:
20 | s.send('Ping')
21 | time.sleep(5)
22 |
--------------------------------------------------------------------------------
/examples/loraNanoGateway/gateway/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/loraNanoGateway/gateway/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import socket
12 | import struct
13 | from network import LoRa
14 |
15 | # A basic package header, B: 1 byte for the deviceId, B: 1 byte for the pkg size, %ds: Formated string for string
16 | _LORA_PKG_FORMAT = "!BB%ds"
17 | # A basic ack package, B: 1 byte for the deviceId, B: 1 bytes for the pkg size, B: 1 byte for the Ok (200) or error messages
18 | _LORA_PKG_ACK_FORMAT = "BBB"
19 |
20 | # Open a LoRa Socket, use rx_iq to avoid listening to our own messages
21 | # Please pick the region that matches where you are using the device:
22 | # Asia = LoRa.AS923
23 | # Australia = LoRa.AU915
24 | # Europe = LoRa.EU868
25 | # United States = LoRa.US915
26 | lora = LoRa(mode=LoRa.LORA, rx_iq=True, region=LoRa.EU868)
27 | lora_sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
28 | lora_sock.setblocking(False)
29 |
30 | while (True):
31 | recv_pkg = lora_sock.recv(512)
32 | if (len(recv_pkg) > 2):
33 | recv_pkg_len = recv_pkg[1]
34 |
35 | device_id, pkg_len, msg = struct.unpack(_LORA_PKG_FORMAT % recv_pkg_len, recv_pkg)
36 |
37 | # If the uart = machine.UART(0, 115200) and os.dupterm(uart) are set in the boot.py this print should appear in the serial port
38 | print('Device: %d - Pkg: %s' % (device_id, msg))
39 |
40 | ack_pkg = struct.pack(_LORA_PKG_ACK_FORMAT, device_id, 1, 200)
41 | lora_sock.send(ack_pkg)
42 |
--------------------------------------------------------------------------------
/examples/loraNanoGateway/node/boot.py:
--------------------------------------------------------------------------------
1 | from machine import UART
2 | import machine
3 | import os
4 |
5 | uart = UART(0, baudrate=115200)
6 | os.dupterm(uart)
7 |
8 | machine.main('main.py')
9 |
--------------------------------------------------------------------------------
/examples/loraNanoGateway/node/main.py:
--------------------------------------------------------------------------------
1 | import os
2 | import socket
3 | import time
4 | import struct
5 | from network import LoRa
6 |
7 | # A basic package header, B: 1 byte for the deviceId, B: 1 bytes for the pkg size
8 | _LORA_PKG_FORMAT = "BB%ds"
9 | _LORA_PKG_ACK_FORMAT = "BBB"
10 | DEVICE_ID = 0x01
11 |
12 |
13 | # Open a Lora Socket, use tx_iq to avoid listening to our own messages
14 | # Please pick the region that matches where you are using the device:
15 | # Asia = LoRa.AS923
16 | # Australia = LoRa.AU915
17 | # Europe = LoRa.EU868
18 | # United States = LoRa.US915
19 | lora = LoRa(mode=LoRa.LORA, tx_iq=True, region=LoRa.EU868)
20 | lora_sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
21 | lora_sock.setblocking(False)
22 |
23 | while(True):
24 | # Package send containing a simple string
25 | msg = "Device 1 Here"
26 | pkg = struct.pack(_LORA_PKG_FORMAT % len(msg), DEVICE_ID, len(msg), msg)
27 | lora_sock.send(pkg)
28 |
29 | # Wait for the response from the gateway. NOTE: For this demo the device does an infinite loop for while waiting the response. Introduce a max_time_waiting for you application
30 | waiting_ack = True
31 | while(waiting_ack):
32 | recv_ack = lora_sock.recv(256)
33 |
34 | if (len(recv_ack) > 0):
35 | device_id, pkg_len, ack = struct.unpack(_LORA_PKG_ACK_FORMAT, recv_ack)
36 | if (device_id == DEVICE_ID):
37 | if (ack == 200):
38 | waiting_ack = False
39 | # If the uart = machine.UART(0, 115200) and os.dupterm(uart) are set in the boot.py this print should appear in the serial port
40 | print("ACK")
41 | else:
42 | waiting_ack = False
43 | # If the uart = machine.UART(0, 115200) and os.dupterm(uart) are set in the boot.py this print should appear in the serial port
44 | print("Message Failed")
45 |
46 | time.sleep(5)
47 |
48 |
--------------------------------------------------------------------------------
/examples/loraabp/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/loraabp/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import socket
13 | import binascii
14 | import struct
15 |
16 | # Initialize LoRa in LORAWAN mode.
17 | # Please pick the region that matches where you are using the device:
18 | # Asia = LoRa.AS923
19 | # Australia = LoRa.AU915
20 | # Europe = LoRa.EU868
21 | # United States = LoRa.US915
22 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
23 |
24 | # create an ABP authentication params
25 | dev_addr = struct.unpack(">l", binascii.unhexlify('00000005'))[0]
26 | nwk_swkey = binascii.unhexlify('2B7E151628AED2A6ABF7158809CF4F3C')
27 | app_swkey = binascii.unhexlify('2B7E151628AED2A6ABF7158809CF4F3C')
28 |
29 | # join a network using ABP (Activation By Personalization)
30 | lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey))
31 |
32 | # create a LoRa socket
33 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
34 |
35 | # set the LoRaWAN data rate
36 | s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5)
37 |
38 | # make the socket non-blocking
39 | s.setblocking(False)
40 |
41 | # send some data
42 | s.send(bytes([0x01, 0x02, 0x03]))
43 |
44 | # get any data received...
45 | data = s.recv(64)
46 | print(data)
47 |
--------------------------------------------------------------------------------
/examples/loramac/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/loramac/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import socket
13 |
14 | # Initialize LoRa in LORA mode.
15 |
16 | # More params can be given, like frequency, tx power and spreading factor.
17 | # Please pick the region that matches where you are using the device:
18 | # Asia = LoRa.AS923
19 | # Australia = LoRa.AU915
20 | # Europe = LoRa.EU868
21 | # United States = LoRa.US915
22 | lora = LoRa(mode=LoRa.LORA, region=LoRa.EU868)
23 |
24 | # create a raw LoRa socket
25 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
26 | s.setblocking(False)
27 |
28 | # send some data
29 | s.send(bytes([0x01, 0x02, 0x03])
30 |
31 | # get any data received...
32 | data = s.recv(64)
33 | print(data)
34 |
--------------------------------------------------------------------------------
/examples/lorawan-nano-gateway/abp_node.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import socket
13 | import binascii
14 | import struct
15 | import time
16 | import config
17 |
18 | # initialize LoRa in LORAWAN mode.
19 | # Please pick the region that matches where you are using the device:
20 | # Asia = LoRa.AS923
21 | # Australia = LoRa.AU915
22 | # Europe = LoRa.EU868
23 | # United States = LoRa.US915
24 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
25 |
26 | # create an ABP authentication params
27 | dev_addr = struct.unpack(">l", binascii.unhexlify('2601147D'))[0]
28 | nwk_swkey = binascii.unhexlify('3C74F4F40CAEA021303BC24284FCF3AF')
29 | app_swkey = binascii.unhexlify('0FFA7072CC6FF69A102A0F39BEB0880F')
30 |
31 | # remove all the non-default channels
32 | for i in range(3, 16):
33 | lora.remove_channel(i)
34 |
35 | # set the 3 default channels to the same frequency
36 | lora.add_channel(0, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
37 | lora.add_channel(1, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
38 | lora.add_channel(2, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
39 |
40 | # join a network using ABP (Activation By Personalization)
41 | lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey))
42 |
43 | # create a LoRa socket
44 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
45 |
46 | # set the LoRaWAN data rate
47 | s.setsockopt(socket.SOL_LORA, socket.SO_DR, config.LORA_NODE_DR)
48 |
49 | # make the socket non-blocking
50 | s.setblocking(False)
51 |
52 | for i in range (200):
53 | pkt = b'PKT #' + bytes([i])
54 | print('Sending:', pkt)
55 | s.send(pkt)
56 | time.sleep(4)
57 | rx, port = s.recvfrom(256)
58 | if rx:
59 | print('Received: {}, on port: {}'.format(rx, port))
60 | time.sleep(6)
61 |
--------------------------------------------------------------------------------
/examples/lorawan-nano-gateway/abp_node_US915.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import LoRa
12 | import socket
13 | import binascii
14 | import struct
15 | import time
16 | import config
17 |
18 | # initialize LoRa in LORAWAN mode.
19 | # Please pick the region that matches where you are using the device:
20 | # Asia = LoRa.AS923
21 | # Australia = LoRa.AU915
22 | # Europe = LoRa.EU868
23 | # United States = LoRa.US915
24 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.US915)
25 |
26 | # create an ABP authentication params
27 | dev_addr = struct.unpack(">l", binascii.unhexlify('2601147D'))[0]
28 | nwk_swkey = binascii.unhexlify('3C74F4F40CAEA021303BC24284FCF3AF')
29 | app_swkey = binascii.unhexlify('0FFA7072CC6FF69A102A0F39BEB0880F')
30 |
31 | # remove all the channels
32 | for channel in range(0, 72):
33 | lora.remove_channel(channel)
34 |
35 | # set all channels to the same frequency (must be before sending the OTAA join request)
36 | for channel in range(0, 72):
37 | lora.add_channel(channel, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=3)
38 |
39 | # join a network using ABP (Activation By Personalization)
40 | lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey))
41 |
42 | # create a LoRa socket
43 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
44 |
45 | # set the LoRaWAN data rate
46 | s.setsockopt(socket.SOL_LORA, socket.SO_DR, config.LORA_NODE_DR)
47 |
48 | # make the socket non-blocking
49 | s.setblocking(False)
50 |
51 | for i in range (200):
52 | pkt = b'PKT #' + bytes([i])
53 | print('Sending:', pkt)
54 | s.send(pkt)
55 | time.sleep(4)
56 | rx, port = s.recvfrom(256)
57 | if rx:
58 | print('Received: {}, on port: {}'.format(rx, port))
59 | time.sleep(6)
60 |
--------------------------------------------------------------------------------
/examples/lorawan-nano-gateway/config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | """ LoPy LoRaWAN Nano Gateway configuration options """
12 |
13 | import machine
14 | import ubinascii
15 |
16 | WIFI_MAC = ubinascii.hexlify(machine.unique_id()).upper()
17 | # Set the Gateway ID to be the first 3 bytes of MAC address + 'FFFE' + last 3 bytes of MAC address
18 | GATEWAY_ID = WIFI_MAC[:6] + "FFFE" + WIFI_MAC[6:12]
19 |
20 | SERVER = 'router.eu.thethings.network'
21 | PORT = 1700
22 |
23 | NTP = "pool.ntp.org"
24 | NTP_PERIOD_S = 3600
25 |
26 | WIFI_SSID = 'my-wifi'
27 | WIFI_PASS = 'my-wifi-password'
28 |
29 | # for EU868
30 | LORA_FREQUENCY = 868100000
31 | LORA_GW_DR = "SF7BW125" # DR_5
32 | LORA_NODE_DR = 5
33 |
34 | # for US915
35 | # LORA_FREQUENCY = 903900000
36 | # LORA_GW_DR = "SF10BW125" # DR_0
37 | # LORA_NODE_DR = 0
38 |
--------------------------------------------------------------------------------
/examples/lorawan-nano-gateway/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | """ LoPy LoRaWAN Nano Gateway example usage """
12 |
13 | import config
14 | from nanogateway import NanoGateway
15 |
16 | if __name__ == '__main__':
17 | nanogw = NanoGateway(
18 | id=config.GATEWAY_ID,
19 | frequency=config.LORA_FREQUENCY,
20 | datarate=config.LORA_GW_DR,
21 | ssid=config.WIFI_SSID,
22 | password=config.WIFI_PASS,
23 | server=config.SERVER,
24 | port=config.PORT,
25 | ntp_server=config.NTP,
26 | ntp_period=config.NTP_PERIOD_S
27 | )
28 |
29 | nanogw.start()
30 | nanogw._log('You may now press ENTER to enter the REPL')
31 | input()
32 |
--------------------------------------------------------------------------------
/examples/lorawan-nano-gateway/otaa_node.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | """ OTAA Node example compatible with the LoPy Nano Gateway """
12 |
13 | from network import LoRa
14 | import socket
15 | import binascii
16 | import struct
17 | import time
18 | import config
19 |
20 | # initialize LoRa in LORAWAN mode.
21 | # Please pick the region that matches where you are using the device:
22 | # Asia = LoRa.AS923
23 | # Australia = LoRa.AU915
24 | # Europe = LoRa.EU868
25 | # United States = LoRa.US915
26 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
27 |
28 | # create an OTA authentication params
29 | dev_eui = binascii.unhexlify('AABBCCDDEEFF7778')
30 | app_eui = binascii.unhexlify('70B3D57EF0003BFD')
31 | app_key = binascii.unhexlify('36AB7625FE770B6881683B495300FFD6')
32 |
33 | # set the 3 default channels to the same frequency (must be before sending the OTAA join request)
34 | lora.add_channel(0, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
35 | lora.add_channel(1, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
36 | lora.add_channel(2, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
37 |
38 | # join a network using OTAA
39 | lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0, dr=config.LORA_NODE_DR)
40 |
41 | # wait until the module has joined the network
42 | while not lora.has_joined():
43 | time.sleep(2.5)
44 | print('Not joined yet...')
45 |
46 | # remove all the non-default channels
47 | for i in range(3, 16):
48 | lora.remove_channel(i)
49 |
50 | # create a LoRa socket
51 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
52 |
53 | # set the LoRaWAN data rate
54 | s.setsockopt(socket.SOL_LORA, socket.SO_DR, config.LORA_NODE_DR)
55 |
56 | # make the socket non-blocking
57 | s.setblocking(False)
58 |
59 | time.sleep(5.0)
60 |
61 | for i in range (200):
62 | pkt = b'PKT #' + bytes([i])
63 | print('Sending:', pkt)
64 | s.send(pkt)
65 | time.sleep(4)
66 | rx, port = s.recvfrom(256)
67 | if rx:
68 | print('Received: {}, on port: {}'.format(rx, port))
69 | time.sleep(6)
70 |
--------------------------------------------------------------------------------
/examples/lorawan-nano-gateway/otaa_node_US915.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | """ OTAA Node example compatible with the LoPy Nano Gateway """
12 |
13 | from network import LoRa
14 | import socket
15 | import binascii
16 | import struct
17 | import time
18 | import config
19 |
20 | # initialize LoRa in LORAWAN mode.
21 | # Please pick the region that matches where you are using the device:
22 | # Asia = LoRa.AS923
23 | # Australia = LoRa.AU915
24 | # Europe = LoRa.EU868
25 | # United States = LoRa.US915
26 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.US915)
27 |
28 | # create an OTA authentication params
29 | dev_eui = binascii.unhexlify('AABBCCDDEEFF7778')
30 | app_eui = binascii.unhexlify('70B3D57EF0003BFD')
31 | app_key = binascii.unhexlify('36AB7625FE770B6881683B495300FFD6')
32 |
33 | # remove all the channels
34 | for channel in range(0, 72):
35 | lora.remove_channel(channel)
36 |
37 | # set all channels to the same frequency (must be before sending the OTAA join request)
38 | for channel in range(0, 72):
39 | lora.add_channel(channel, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=3)
40 |
41 | # join a network using OTAA
42 | lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0, dr=config.LORA_NODE_DR)
43 |
44 | # wait until the module has joined the network
45 | join_wait = 0
46 | while True:
47 | time.sleep(2.5)
48 | if not lora.has_joined():
49 | print('Not joined yet...')
50 | join_wait += 1
51 | if join_wait == 5:
52 | lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_eui, app_key), timeout=0, dr=config.LORA_NODE_DR)
53 | join_wait = 0
54 | else:
55 | break
56 |
57 | # create a LoRa socket
58 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
59 |
60 | # set the LoRaWAN data rate
61 | s.setsockopt(socket.SOL_LORA, socket.SO_DR, config.LORA_NODE_DR)
62 |
63 | # make the socket non-blocking
64 | s.setblocking(False)
65 |
66 | time.sleep(5.0)
67 |
68 | for i in range (200):
69 | pkt = b'PKT #' + bytes([i])
70 | print('Sending:', pkt)
71 | s.send(pkt)
72 | time.sleep(4)
73 | rx, port = s.recvfrom(256)
74 | if rx:
75 | print('Received: {}, on port: {}'.format(rx, port))
76 | time.sleep(6)
77 |
--------------------------------------------------------------------------------
/examples/lorawan-regional-examples/main_AS923.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | """
12 | OTAA Node example as per LoRaWAN AS923 regional specification
13 | - compatible with the LoPy Nano Gateway and all other LoraWAN gateways
14 | - tested works with a LoRaServer, shall works on TTN servers
15 | """
16 |
17 | from network import LoRa
18 | import socket
19 | import binascii
20 | import struct
21 | import time
22 |
23 | LORA_CHANNEL = 1
24 | LORA_NODE_DR = 4
25 |
26 | '''
27 | utility function to setup the lora channels
28 | '''
29 | def prepare_channels(lora, channel, data_rate):
30 |
31 | AS923_FREQUENCIES = [
32 | { "chan": 1, "fq": "923200000" },
33 | { "chan": 2, "fq": "923400000" },
34 | { "chan": 3, "fq": "922200000" },
35 | { "chan": 4, "fq": "922400000" },
36 | { "chan": 5, "fq": "922600000" },
37 | { "chan": 6, "fq": "922800000" },
38 | { "chan": 7, "fq": "923000000" },
39 | { "chan": 8, "fq": "922000000" },
40 | ]
41 |
42 | if not channel in range(0, 9):
43 | raise RuntimeError("channels should be in 1-8 for AS923")
44 |
45 | if channel == 0:
46 | import uos
47 | channel = (struct.unpack('B',uos.urandom(1))[0] % 7) + 1
48 |
49 | for i in range(0, 8):
50 | lora.remove_channel(i)
51 |
52 | upstream = (item for item in AS923_FREQUENCIES if item["chan"] == channel).__next__()
53 |
54 | # set default channels frequency
55 | lora.add_channel(int(upstream.get('chan')), frequency=int(upstream.get('fq')), dr_min=0, dr_max=data_rate)
56 |
57 | return lora
58 |
59 | '''
60 | call back for handling RX packets
61 | '''
62 | def lora_cb(lora):
63 | events = lora.events()
64 | if events & LoRa.RX_PACKET_EVENT:
65 | if lora_socket is not None:
66 | frame, port = lora_socket.recvfrom(512) # longuest frame is +-220
67 | print(port, frame)
68 | if events & LoRa.TX_PACKET_EVENT:
69 | print("tx_time_on_air: {} ms @dr {}", lora.stats().tx_time_on_air, lora.stats().sftx)
70 |
71 | '''
72 | Main operations: this is sample code for LoRaWAN on AS923
73 | '''
74 |
75 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.AS923, device_class=LoRa.CLASS_C, adr=False, tx_power=20)
76 |
77 | # create an OTA authentication params
78 | dev_eui = binascii.unhexlify('0000000000000000')
79 | app_key = binascii.unhexlify('a926e5bb85271f2d') # not used leave empty loraserver.io
80 | nwk_key = binascii.unhexlify('a926e5bb85271f2da0440f2f4200afe3')
81 |
82 | # join a network using OTAA
83 | lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_key, nwk_key), timeout=0, dr=2) # AS923 always joins at DR2
84 |
85 | prepare_channels(lora, LORA_CHANNEL, LORA_NODE_DR)
86 |
87 | # wait until the module has joined the network
88 | print('Over the air network activation ... ', end='')
89 | while not lora.has_joined():
90 | time.sleep(2.5)
91 | print('.', end='')
92 | print('')
93 |
94 | # create a LoRa socket
95 | lora_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
96 |
97 | # set the LoRaWAN data rate
98 | lora_socket.setsockopt(socket.SOL_LORA, socket.SO_DR, LORA_NODE_DR)
99 |
100 | # msg are confirmed at the FMS level
101 | lora_socket.setsockopt(socket.SOL_LORA, socket.SO_CONFIRMED, 0)
102 |
103 | # make the socket non blocking y default
104 | lora_socket.setblocking(False)
105 |
106 | lora.callback(trigger=( LoRa.RX_PACKET_EVENT |
107 | LoRa.TX_PACKET_EVENT |
108 | LoRa.TX_FAILED_EVENT ), handler=lora_cb)
109 |
110 | time.sleep(4) # this timer is important and caused me some trouble ...
111 |
112 | for i in range(0, 1000):
113 | pkt = struct.pack('>H', i)
114 | print('Sending:', pkt)
115 | lora_socket.send(pkt)
116 | time.sleep(300)
117 |
--------------------------------------------------------------------------------
/examples/lorawan-regional-examples/main_AU915.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | """
12 | OTAA Node example as per LoRaWAN AU915 regional specification
13 | - tested works with a LoRaServer, shall works on TTN servers
14 | - This example uses 8 channels so you will need an 8 channel GW
15 | (not a 1 channel GW like the NanoGateway)
16 | """
17 |
18 | from network import LoRa
19 | import socket
20 | import binascii
21 | import struct
22 | import time
23 |
24 | LORA_FREQUENCY = 915200000 # start of the 1st subband
25 | LORA_NODE_DR = 4
26 | '''
27 | utility function to setup the lora channels
28 | '''
29 | def prepare_channels(lora, channel, data_rate):
30 |
31 | AU915_FREQUENCIES = [
32 | { "chan": 64, "fq": "915200000" }
33 | ]
34 | if not channel in range(64,65):
35 | raise RuntimeError("only channel 64 is implemented in this example)")
36 | upstream = (item for item in AU915_FREQUENCIES if item["chan"] == channel).__next__()
37 |
38 | lora.add_channel(int(upstream.get('chan')), frequency=int(upstream.get('fq')), dr_min=0, dr_max=int(data_rate))
39 | print("*** Adding channel up %s %s" % (upstream.get('chan'), upstream.get('fq')))
40 |
41 | for index in range(0, 71):
42 | if index != upstream.get('chan'):
43 | lora.remove_channel(index)
44 |
45 | return lora
46 |
47 | '''
48 | call back for handling RX packets
49 | '''
50 | def lora_cb(lora):
51 | events = lora.events()
52 | if events & LoRa.RX_PACKET_EVENT:
53 | if lora_socket is not None:
54 | frame, port = lora_socket.recvfrom(512) # longuest frame is +-220
55 | print(port, frame)
56 | if events & LoRa.TX_PACKET_EVENT:
57 | print("tx_time_on_air: {} ms @dr {}", lora.stats().tx_time_on_air, lora.stats().sftx)
58 |
59 |
60 | '''
61 | Main operations: this is sample code for LoRaWAN on AU915
62 | '''
63 |
64 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.AU915, device_class=LoRa.CLASS_C)
65 |
66 | # create an OTA authentication params
67 | dev_eui = binascii.unhexlify('0000000000000000')
68 | app_key = binascii.unhexlify('a926e5bb85271f2d') # not used leave empty loraserver.io
69 | nwk_key = binascii.unhexlify('a926e5bb85271f2da0440f2f4200afe3')
70 |
71 | prepare_channels(lora, 64, 5)
72 |
73 | # join a network using OTAA
74 | lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_key, nwk_key), timeout=0, dr=0) # DR is 2 in v1.1rb but 0 worked for ne
75 |
76 | # wait until the module has joined the network
77 | print('Over the air network activation ... ', end='')
78 | while not lora.has_joined():
79 | time.sleep(2.5)
80 | print('.', end='')
81 | print('')
82 |
83 | for i in range(0, 8):
84 | fq = LORA_FREQUENCY + (i * 200000)
85 | lora.add_channel(i, frequency=fq, dr_min=0, dr_max=LORA_NODE_DR)
86 | print("AU915 Adding channel up %s %s" % (i, fq))
87 |
88 |
89 | # create a LoRa socket
90 | lora_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
91 |
92 | # set the LoRaWAN data rate
93 | lora_socket.setsockopt(socket.SOL_LORA, socket.SO_DR, LORA_NODE_DR)
94 |
95 | # msg are confirmed at the FMS level
96 | lora_socket.setsockopt(socket.SOL_LORA, socket.SO_CONFIRMED, 0)
97 |
98 | # make the socket non blocking y default
99 | lora_socket.setblocking(False)
100 |
101 | lora.callback(trigger=( LoRa.RX_PACKET_EVENT |
102 | LoRa.TX_PACKET_EVENT |
103 | LoRa.TX_FAILED_EVENT ), handler=lora_cb)
104 |
105 | time.sleep(4) # this timer is important and caused me some trouble ...
106 |
107 | for i in range(0, 1000):
108 | pkt = struct.pack('>H', i)
109 | print('Sending:', pkt)
110 | lora_socket.send(pkt)
111 | time.sleep(300)
112 |
--------------------------------------------------------------------------------
/examples/lorawan-regional-examples/main_EU868.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | """
12 | OTAA Node example as per LoRaWAN EU868 regional specification
13 | - compatible with the LoPy Nano Gateway and all other LoraWAN gateways
14 | - tested works with a LoRaServer and TTN servers
15 | """
16 |
17 | from network import LoRa
18 | import socket
19 | import binascii
20 | import struct
21 | import time
22 |
23 | LORA_CHANNEL = 0 # zero = random
24 | LORA_NODE_DR = 4
25 | '''
26 | utility function to setup the lora channels
27 | '''
28 | def prepare_channels(lora, channel, data_rate):
29 | EU868_FREQUENCIES = [
30 | { "chan": 1, "fq": "868100000" },
31 | { "chan": 2, "fq": "868300000" },
32 | { "chan": 3, "fq": "868500000" },
33 | { "chan": 4, "fq": "867100000" },
34 | { "chan": 5, "fq": "867300000" },
35 | { "chan": 6, "fq": "867500000" },
36 | { "chan": 7, "fq": "867700000" },
37 | { "chan": 8, "fq": "867900000" },
38 | ]
39 | if not channel in range(0, 9):
40 | raise RuntimeError("channels should be in 0-8 for EU868")
41 |
42 | if channel == 0:
43 | import uos
44 | channel = (struct.unpack('B',uos.urandom(1))[0] % 7) + 1
45 |
46 | upstream = (item for item in EU868_FREQUENCIES if item["chan"] == channel).__next__()
47 |
48 | # set the 3 default channels to the same frequency
49 | lora.add_channel(0, frequency=int(upstream.get('fq')), dr_min=0, dr_max=5)
50 | lora.add_channel(1, frequency=int(upstream.get('fq')), dr_min=0, dr_max=5)
51 | lora.add_channel(2, frequency=int(upstream.get('fq')), dr_min=0, dr_max=5)
52 |
53 | for i in range(3, 16):
54 | lora.remove_channel(i)
55 |
56 | return lora
57 |
58 | '''
59 | call back for handling RX packets
60 | '''
61 | def lora_cb(lora):
62 | events = lora.events()
63 | if events & LoRa.RX_PACKET_EVENT:
64 | if lora_socket is not None:
65 | frame, port = lora_socket.recvfrom(512) # longuest frame is +-220
66 | print(port, frame)
67 | if events & LoRa.TX_PACKET_EVENT:
68 | print("tx_time_on_air: {} ms @dr {}", lora.stats().tx_time_on_air, lora.stats().sftx)
69 |
70 |
71 | '''
72 | Main operations: this is sample code for LoRaWAN on EU868
73 | '''
74 |
75 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868, device_class=LoRa.CLASS_C)
76 |
77 | # create an OTA authentication params
78 | dev_eui = binascii.unhexlify('0000000000000000')
79 | app_key = binascii.unhexlify('a926e5bb85271f2d') # not used leave empty loraserver.io
80 | nwk_key = binascii.unhexlify('a926e5bb85271f2da0440f2f4200afe3')
81 |
82 | prepare_channels(lora, 1, LORA_NODE_DR)
83 |
84 | # join a network using OTAA
85 | lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_key, nwk_key), timeout=0, dr=LORA_NODE_DR) # DR is 2 in v1.1rb but 0 worked for ne
86 |
87 | # wait until the module has joined the network
88 | print('Over the air network activation ... ', end='')
89 | while not lora.has_joined():
90 | time.sleep(2.5)
91 | print('.', end='')
92 | print('')
93 |
94 | # create a LoRa socket
95 | lora_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
96 |
97 | # set the LoRaWAN data rate
98 | lora_socket.setsockopt(socket.SOL_LORA, socket.SO_DR, LORA_NODE_DR)
99 |
100 | # msg are confirmed at the FMS level
101 | lora_socket.setsockopt(socket.SOL_LORA, socket.SO_CONFIRMED, 0)
102 |
103 | # make the socket non blocking y default
104 | lora_socket.setblocking(False)
105 |
106 | lora.callback(trigger=( LoRa.RX_PACKET_EVENT |
107 | LoRa.TX_PACKET_EVENT |
108 | LoRa.TX_FAILED_EVENT ), handler=lora_cb)
109 |
110 | time.sleep(4) # this timer is important and caused me some trouble ...
111 |
112 | for i in range(0, 1000):
113 | pkt = struct.pack('>H', i)
114 | print('Sending:', pkt)
115 | lora_socket.send(pkt)
116 | time.sleep(300)
117 |
--------------------------------------------------------------------------------
/examples/lorawan-regional-examples/main_US915.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | """
12 | OTAA Node example as per LoRaWAN US915 regional specification
13 | - tested works with a LoRaServer, shall works on TTN servers
14 | - This example uses 8 channels so you will need an 8 channel GW
15 | (not a 1 channel GW like the NanoGateway)
16 | """
17 |
18 | from network import LoRa
19 | import socket
20 | import binascii
21 | import struct
22 | import time
23 |
24 | LORA_FREQUENCY = 916800000 # start of the 1st subband
25 | LORA_NODE_DR = 4
26 | '''
27 | utility function to setup the lora channels
28 | '''
29 | def prepare_channels(lora, channel, data_rate):
30 |
31 | US915_FREQUENCIES = [
32 | { "chan": 64, "fq": "902300000" }
33 | ]
34 | if not channel in range(64,65):
35 | raise RuntimeError("channels should be in 64 for US915 (only subband 1 is implemented in this example)")
36 | upstream = (item for item in US915_FREQUENCIES if item["chan"] == channel).__next__()
37 |
38 | lora.add_channel(int(upstream.get('chan')), frequency=int(upstream.get('fq')), dr_min=0, dr_max=int(data_rate))
39 | print("*** Adding channel up %s %s" % (upstream.get('chan'), upstream.get('fq')))
40 |
41 | for index in range(0, 71):
42 | if index != upstream.get('chan'):
43 | lora.remove_channel(index)
44 |
45 | return lora
46 |
47 | '''
48 | call back for handling RX packets
49 | '''
50 | def lora_cb(lora):
51 | events = lora.events()
52 | if events & LoRa.RX_PACKET_EVENT:
53 | if lora_socket is not None:
54 | frame, port = lora_socket.recvfrom(512) # longuest frame is +-220
55 | print(port, frame)
56 | if events & LoRa.TX_PACKET_EVENT:
57 | print("tx_time_on_air: {} ms @dr {}", lora.stats().tx_time_on_air, lora.stats().sftx)
58 |
59 |
60 | '''
61 | Main operations: this is sample code for LoRaWAN on US915
62 | '''
63 |
64 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.US915, device_class=LoRa.CLASS_C)
65 |
66 | # create an OTA authentication params
67 | dev_eui = binascii.unhexlify('0000000000000000')
68 | app_key = binascii.unhexlify('a926e5bb85271f2d') # not used leave empty loraserver.io
69 | nwk_key = binascii.unhexlify('a926e5bb85271f2da0440f2f4200afe3')
70 |
71 | prepare_channels(lora, 64, 0)
72 |
73 | # join a network using OTAA
74 | lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_key, nwk_key), timeout=0, dr=0) # US915 always joins at DR2
75 |
76 | for i in range(0, 8):
77 | fq = LORA_FREQUENCY + (i * 200000)
78 | lora.add_channel(i, frequency=fq, dr_min=0, dr_max=LORA_NODE_DR)
79 | print("US915 Adding channel up %s %s" % (i, fq))
80 |
81 | # wait until the module has joined the network
82 | print('Over the air network activation ... ', end='')
83 | while not lora.has_joined():
84 | time.sleep(2.5)
85 | print('.', end='')
86 | print('')
87 |
88 | lora_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
89 |
90 | # set the LoRaWAN data rate
91 | # create a LoRa socket
92 | lora_socket.setsockopt(socket.SOL_LORA, socket.SO_DR, LORA_NODE_DR)
93 |
94 | # msg are confirmed at the FMS level
95 | lora_socket.setsockopt(socket.SOL_LORA, socket.SO_CONFIRMED, 0)
96 |
97 | # make the socket non blocking y default
98 | lora_socket.setblocking(False)
99 |
100 | lora.callback(trigger=( LoRa.RX_PACKET_EVENT |
101 | LoRa.TX_PACKET_EVENT |
102 | LoRa.TX_FAILED_EVENT ), handler=lora_cb)
103 |
104 | time.sleep(4) # this timer is important and caused me some trouble ...
105 |
106 | for i in range(0, 1000):
107 | pkt = struct.pack('>H', i)
108 | print('Sending:', pkt)
109 | lora_socket.send(pkt)
110 | time.sleep(300)
111 |
--------------------------------------------------------------------------------
/examples/mqtt/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/mqtt/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import WLAN
12 | from mqtt import MQTTClient
13 | import machine
14 | import time
15 |
16 | def settimeout(duration):
17 | pass
18 |
19 | wlan = WLAN(mode=WLAN.STA)
20 | wlan.antenna(WLAN.EXT_ANT)
21 | wlan.connect("yourwifinetwork", auth=(WLAN.WPA2, "wifipassword"), timeout=5000)
22 |
23 | while not wlan.isconnected():
24 | machine.idle()
25 |
26 | print("Connected to Wifi\n")
27 | client = MQTTClient("demo", "broker.hivemq.com", port=1883)
28 | client.settimeout = settimeout
29 | client.connect()
30 |
31 | while True:
32 | print("Sending ON")
33 | client.publish("/lights", "ON")
34 | time.sleep(1)
35 | print("Sending OFF")
36 | client.publish("/lights", "OFF")
37 | time.sleep(1)
38 |
--------------------------------------------------------------------------------
/examples/onlineLog/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/examples/onlineLog/__init__.py
--------------------------------------------------------------------------------
/examples/onlineLog/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 | from network import WLAN
15 |
16 | uart = UART(0, baudrate=115200)
17 | os.dupterm(uart)
18 |
19 | wifi_ssid = 'YOURWIFISSID'
20 | wifi_pass = 'YOURWIFIPASSWORD'
21 |
22 | if machine.reset_cause() != machine.SOFT_RESET:
23 |
24 | wlan = WLAN(mode=WLAN.STA)
25 |
26 | wlan.connect(wifi_ssid, auth=(WLAN.WPA2, wifi_pass), timeout=5000)
27 |
28 | while not wlan.isconnected():
29 | machine.idle()
30 |
31 |
32 | machine.main('main.py')
33 |
--------------------------------------------------------------------------------
/examples/onlineLog/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import time
12 | import machine
13 | from onewire import DS18X20
14 | from onewire import OneWire
15 |
16 | import usocket as socket
17 |
18 | publicKey = 'SPARKFUNCHANNELPUBLICKEY'
19 | privateKey = 'SPARKFUNCAHNNELPRIVATEKEY'
20 |
21 |
22 | #DS18B20 data line connected to pin P10
23 | ow = OneWire(machine.Pin('P10'))
24 | temp = DS18X20(ow)
25 |
26 | while True:
27 | temp.start_conversion()
28 | time.sleep(1)
29 | tempValue = temp.read_temp_async()/100.0
30 | u = 'POST /input/%s?private_key=%s&temp=%f HTTP/1.0\n\n'%( publicKey, privateKey, tempValue)
31 |
32 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
33 | ai = socket.getaddrinfo("data.sparkfun.com", 80)
34 | addr = ai[0][4]
35 | s.connect(addr)
36 | s.sendall(u)
37 | status = s.recv(4096)
38 | s.close()
39 | print('POST temp=%f'%tempValue)
40 | time.sleep(10)
41 |
--------------------------------------------------------------------------------
/examples/pytrack_pysense_accelerometer/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import time
12 |
13 | # From:https://github.com/pycom/pycom-libraries
14 | from LIS2HH12 import LIS2HH12
15 | from pytrack import Pytrack
16 |
17 | py = Pytrack()
18 | acc = LIS2HH12()
19 | while True:
20 | pitch = acc.pitch()
21 | roll = acc.roll()
22 | print('{},{}'.format(pitch,roll))
23 | time.sleep_ms(100)
24 |
--------------------------------------------------------------------------------
/examples/pytrack_pysense_accelerometer/visualiser/README.md:
--------------------------------------------------------------------------------
1 | **About**
2 |
3 | This folder contains a [Processing](https://processing.org/) sketch that takes in roll and pitch values from a serial port in comma separated value (CSV) format, and tilts a 3D model accordingly.
4 |
5 | **Requriements**
6 |
7 | - Processing (tested on v3.3.6)
8 | - Python Mode for Processing
9 |
10 | **Setup**
11 |
12 | Once you have Processing with python mode installed, you will need to open this sketch and change the SERIAL_DEVICE variable to match the serial port of your device. Once you have done this just run the sketch and a 3D model should appear that tilts with the board.
13 |
--------------------------------------------------------------------------------
/examples/pytrack_pysense_accelerometer/visualiser/pycomLogoGoInventGrey800.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/examples/pytrack_pysense_accelerometer/visualiser/pycomLogoGoInventGrey800.png
--------------------------------------------------------------------------------
/examples/pytrack_pysense_accelerometer/visualiser/sketch.properties:
--------------------------------------------------------------------------------
1 | mode=Python
2 | mode.id=jycessing.mode.PythonMode
3 |
--------------------------------------------------------------------------------
/examples/pytrack_pysense_accelerometer/visualiser/visualiser.pyde:
--------------------------------------------------------------------------------
1 | add_library('serial')
2 | SERIAL_DEVICE='/dev/tty.usbmodemPy343431'
3 |
4 | def setup():
5 | global my_port
6 |
7 | #Connect to serial device
8 | for dev in Serial.list():
9 | if dev == SERIAL_DEVICE:
10 | my_port = Serial(this, dev, 115200)
11 | print("Connected to '{}'".format(SERIAL_DEVICE))
12 | break
13 | else:
14 | msg = "Could not find serial port '{}'"
15 | raise Exception(msg.format(SERIAL_DEVICE))
16 |
17 | # Clear the serial buffer and consume first
18 | # line incase we missed the start of it
19 | my_port.clear()
20 | my_port.readStringUntil(10)
21 |
22 | #Setup window
23 | size(400, 400, P3D)
24 |
25 | lastRoll = 0
26 | lastPitch = 0
27 |
28 | def draw():
29 | global lastRoll, lastPitch
30 |
31 | #Get new reading from serial port
32 | line = my_port.readStringUntil(10)
33 | if line != None:
34 | line = line.split(',')
35 | if len(line) == 2:
36 | pitch, roll = line
37 | try:
38 | pitch = float(pitch)
39 | roll = float(roll)
40 | lastPitch = pitch
41 | lastRoll = roll
42 | except Exception:
43 | pass
44 |
45 | background(0)
46 | noStroke()
47 |
48 | # Put view in the middle of the screen
49 | # and far enough away to see properly
50 | translate(width/2, height/2, -100)
51 |
52 | # Default to last proper result
53 | pitch = lastPitch
54 | roll = lastRoll
55 |
56 | # Rotate view
57 | rotateX(-radians(pitch))
58 | rotateZ(radians(roll))
59 |
60 | # Zoom
61 | scale(190)
62 |
63 | # Draw the box
64 | drawBox(0.6, 0.1, 1)
65 |
66 | def drawBox(w, h, d):
67 | # Front
68 | beginShape(QUADS)
69 | fill(255,0,0)
70 | vertex(-w, -h, d)
71 | vertex( w, -h, d)
72 | vertex( w, h, d)
73 | vertex(-w, h, d)
74 | endShape()
75 |
76 | # Back
77 | beginShape(QUADS)
78 | fill(255,255,0)
79 | vertex( w, -h, -d)
80 | vertex(-w, -h, -d)
81 | vertex(-w, h, -d)
82 | vertex( w, h, -d)
83 | endShape()
84 |
85 | # Bottom
86 | beginShape(QUADS)
87 | fill( 255,0,255)
88 | vertex(-w, h, d)
89 | vertex( w, h, d)
90 | vertex( w, h, -d)
91 | vertex(-w, h, -d)
92 | endShape()
93 |
94 | # Top
95 | img = loadImage("pycomLogoGoInventGrey800.png");
96 | blendMode(REPLACE)
97 | textureMode(NORMAL)
98 | textureWrap(CLAMP)
99 | beginShape(QUADS)
100 | texture(img)
101 | tint(255,255,255)
102 | vertex(-w, -h, -d, -1, -0.2)
103 | vertex( w, -h, -d, 2, -0.2)
104 | vertex( w, -h, d, 2, 1.2)
105 | vertex(-w, -h, d, -1, 1.2)
106 | endShape()
107 |
108 | # Right
109 | beginShape(QUADS)
110 | fill(0,0,255)
111 | vertex( w, -h, d)
112 | vertex( w, -h, -d)
113 | vertex( w, h, -d)
114 | vertex( w, h, d)
115 | endShape()
116 |
117 | # Left
118 | beginShape(QUADS)
119 | fill(0,255,0)
120 | vertex(-w, -h, -d)
121 | vertex(-w, -h, d)
122 | vertex(-w, h, d)
123 | vertex(-w, h, -d)
124 | endShape()
125 |
--------------------------------------------------------------------------------
/examples/sigfoxUplink/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/sigfoxUplink/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from network import Sigfox
12 | import socket
13 |
14 | # init Sigfox for RCZ1 (Europe)
15 | sigfox = Sigfox(mode=Sigfox.SIGFOX, rcz=Sigfox.RCZ1)
16 |
17 | # create a Sigfox socket
18 | s = socket.socket(socket.AF_SIGFOX, socket.SOCK_RAW)
19 |
20 | # make the socket blocking
21 | s.setblocking(True)
22 |
23 | # configure it as uplink only
24 | s.setsockopt(socket.SOL_SIGFOX, socket.SO_RX, False)
25 |
26 | # send some bytes
27 | s.send(bytes([0x01, 0x02, 0x03]))
28 |
--------------------------------------------------------------------------------
/examples/threading/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/examples/threading/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import _thread
12 | import time
13 |
14 | def th_func(delay, id):
15 | while True:
16 | time.sleep(delay)
17 | print('Running thread %d' % id)
18 |
19 | for i in range(2):
20 | _thread.start_new_thread(th_func, (i + 1, i))
--------------------------------------------------------------------------------
/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/img/logo.png
--------------------------------------------------------------------------------
/lib/ADS1115/ADS1115.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | # Interface for ADS1115 16-bit I2C ADC
12 |
13 | class ADS1115:
14 |
15 | def __init__(self, i2c, address=0x49, gain=0):
16 | # Modified to work in Wipy2.0
17 | self.i2c = i2c
18 | self.address = address
19 | self.gain = gain # 0 --> 2/3 6.144V
20 |
21 | def _write_register(self, register, value):
22 | data = ustruct.pack('>BH', register, value)
23 | self.i2c.writeto(self.address, data)
24 |
25 | def _read_register(self, register):
26 | data = self.i2c.readfrom_mem(self.address, register, 2 )
27 | return ustruct.unpack('>h', data)[0]
28 |
--------------------------------------------------------------------------------
/lib/ADS1115/boot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import UART
12 | import machine
13 | import os
14 |
15 | uart = UART(0, baudrate=115200)
16 | os.dupterm(uart)
17 |
18 | machine.main('main.py')
19 |
--------------------------------------------------------------------------------
/lib/ALSPT19/ALSPT19.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import ADC
12 | import time
13 |
14 | class ALSPT19(object):
15 | def __init__(self, pin_name):
16 | adc = ADC()
17 | self.pin = adc.channel(pin=pin_name, attn=ADC.ATTN_11DB, bits=12)
18 | self.threshold = None
19 |
20 | def calibrate(self, samples=300):
21 | max_val = 0
22 | for _ in range(samples):
23 | val = self.pin()
24 | if val > max_val:
25 | max_val = val
26 | time.sleep_ms(10)
27 |
28 | self.threshold = max_val * 1.2
29 |
30 | def is_on(self):
31 | if self.pin() > self.threshold:
32 | return True
33 | return False
34 |
--------------------------------------------------------------------------------
/lib/TB6612FNG/TB6612FNG.py:
--------------------------------------------------------------------------------
1 | from machine import PWM, Pin
2 |
3 | class _TB6612FNG_channel(object):
4 | _pwm_id = 0
5 | _pwm = PWM(0, frequency=5000)
6 |
7 | @classmethod
8 | def id(cls):
9 | if cls._pwm_id > 7:
10 | raise Exception("Cannot create more pwm channels")
11 |
12 | temp = cls._pwm_id
13 | cls._pwm_id += 1
14 | return temp
15 |
16 | def __init__(self, pin_1, pin_2, pwm_pin):
17 | self.pin_1 = Pin(pin_1, mode=Pin.OUT, pull=None)
18 | self.pin_1.value(0)
19 |
20 | self.pin_2 = Pin(pin_2, mode=Pin.OUT, pull=None)
21 | self.pin_1.value(0)
22 |
23 | self.pwm = TB6612FNG_channel._pwm.channel(self.id(), pin=pwm_pin, duty_cycle=1)
24 | self.pwm.duty_cycle(0)
25 |
26 | def clockwise(self):
27 | self.pin_1.value(1)
28 | self.pin_2.value(0)
29 |
30 | def anticlockwise(self):
31 | self.pin_1.value(0)
32 | self.pin_2.value(1)
33 |
34 | def short_break(self):
35 | self.pin_1.value(1)
36 | self.pin_2.value(1)
37 |
38 | def freewheel(self):
39 | self.pin_1.value(0)
40 | self.pin_2.value(0)
41 |
42 | def duty_cycle(self, *args, **kwargs):
43 | return self.pwm.duty_cycle(*args, **kwargs)
44 |
45 |
46 | class TB6612FNG(object):
47 |
48 | def __init__(self, a_1, a_2, a_pwm, b_1, b_2, b_pwm, standby_pin):
49 | self._standby = Pin(standby_pin, mode=Pin.OUT, pull=None)
50 | self._standby.value(1)
51 | self.channelA = _TB6612FNG_channel(a_1, a_2, a_pwm)
52 | self.channelB = _TB6612FNG_channel(b_1, b_2, b_pwm)
53 |
54 | def standby(self, *args):
55 | return self._standby.value(*args)
56 |
--------------------------------------------------------------------------------
/lib/mqtt_aws/MQTTConst.py:
--------------------------------------------------------------------------------
1 |
2 | # - Protocol types
3 | MQTTv3_1 = 3
4 | MQTTv3_1_1 = 4
5 |
6 | # - OfflinePublishQueueing drop behavior
7 | DROP_OLDEST = 0
8 | DROP_NEWEST = 1
9 |
10 | # Message types
11 | MSG_CONNECT = 0x10
12 | MSG_CONNACK = 0x20
13 | MSG_PUBLISH = 0x30
14 | MSG_PUBACK = 0x40
15 | MSG_PUBREC = 0x50
16 | MSG_PUBREL = 0x60
17 | MSG_PUBCOMP = 0x70
18 | MSG_SUBSCRIBE = 0x80
19 | MSG_SUBACK = 0x90
20 | MSG_UNSUBSCRIBE = 0xA0
21 | MSG_UNSUBACK = 0xB0
22 | MSG_PINGREQ = 0xC0
23 | MSG_PINGRESP = 0xD0
24 | MSG_DISCONNECT = 0xE0
25 |
26 | # Connection state
27 | STATE_CONNECTED = 0x01
28 | STATE_CONNECTING = 0x02
29 | STATE_DISCONNECTED = 0x03
30 |
31 | class UUID:
32 | int_ = int
33 | bytes_ = bytes
34 |
35 | def __init__(self, bytes=None, version=None):
36 |
37 | self._int = UUID.int_.from_bytes(bytes, 'big')
38 |
39 | self._int &= ~(0xc000 << 48)
40 | self._int |= 0x8000 << 48
41 | self._int &= ~(0xf000 << 64)
42 | self._int |= version << 76
43 |
44 | @property
45 | def urn(self):
46 | return 'urn:uuid:' + str(self)
47 |
--------------------------------------------------------------------------------
/lib/mqtt_aws/MQTTLib.py:
--------------------------------------------------------------------------------
1 | import MQTTConst as mqttConst
2 | import MQTTClient as mqttClient
3 | import MQTTShadowManager as shadowManager
4 | import MQTTDeviceShadow as deviceShadow
5 |
6 | class AWSIoTMQTTClient:
7 |
8 | def __init__(self, clientID, protocolType=mqttConst.MQTTv3_1_1, useWebsocket=False, cleanSession=True):
9 | self._mqttClient = mqttClient.MQTTClient(clientID, cleanSession, protocolType)
10 |
11 | # Configuration APIs
12 | def configureLastWill(self, topic, payload, QoS):
13 | self._mqttClient.setLastWill(topic, payload, QoS)
14 |
15 | def clearLastWill(self):
16 | self._mqttClient.clearLastWill()
17 |
18 | def configureEndpoint(self, hostName, portNumber):
19 | self._mqttClient.configEndpoint(hostName, portNumber)
20 |
21 | def configureIAMCredentials(self, AWSAccessKeyID, AWSSecretAccessKey, AWSSessionToken=""):
22 | self._mqttClient.configIAMCredentials(AWSAccessKeyID, AWSSecretAccessKey, AWSSessionToken)
23 |
24 | def configureCredentials(self, CAFilePath, KeyPath="", CertificatePath=""): # Should be good for MutualAuth certs config and Websocket rootCA config
25 | self._mqttClient.configCredentials(CAFilePath, KeyPath, CertificatePath)
26 |
27 | def configureAutoReconnectBackoffTime(self, baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond):
28 | self._mqttClient.setBackoffTiming(baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond)
29 |
30 | def configureOfflinePublishQueueing(self, queueSize, dropBehavior=mqttConst.DROP_NEWEST):
31 | self._mqttClient.setOfflinePublishQueueing(queueSize, dropBehavior)
32 |
33 | def configureDrainingFrequency(self, frequencyInHz):
34 | self._mqttClient.setDrainingIntervalSecond(1/float(frequencyInHz))
35 |
36 | def configureConnectDisconnectTimeout(self, timeoutSecond):
37 | self._mqttClient.setConnectDisconnectTimeoutSecond(timeoutSecond)
38 |
39 | def configureMQTTOperationTimeout(self, timeoutSecond):
40 | self._mqttClient.setMQTTOperationTimeoutSecond(timeoutSecond)
41 |
42 | # MQTT functionality APIs
43 | def connect(self, keepAliveIntervalSecond=30):
44 | return self._mqttClient.connect(keepAliveIntervalSecond)
45 |
46 | def disconnect(self):
47 | return self._mqttClient.disconnect()
48 |
49 | def publish(self, topic, payload, QoS):
50 | return self._mqttClient.publish(topic, payload, QoS, False) # Disable retain for publish by now
51 |
52 | def subscribe(self, topic, QoS, callback):
53 | return self._mqttClient.subscribe(topic, QoS, callback)
54 |
55 | def unsubscribe(self, topic):
56 | return self._mqttClient.unsubscribe(topic)
57 |
58 |
59 | class AWSIoTMQTTShadowClient:
60 |
61 | def __init__(self, clientID, protocolType=mqttConst.MQTTv3_1_1, useWebsocket=False, cleanSession=True):
62 | # AWSIOTMQTTClient instance
63 | self._AWSIoTMQTTClient = AWSIoTMQTTClient(clientID, protocolType, useWebsocket, cleanSession)
64 | # Configure it to disable offline Publish Queueing
65 | self._AWSIoTMQTTClient.configureOfflinePublishQueueing(0) # Disable queueing, no queueing for time-sentive shadow messages
66 | self._AWSIoTMQTTClient.configureDrainingFrequency(10)
67 | # Now retrieve the configured mqttCore and init a shadowManager instance
68 | self._shadowManager = shadowManager.shadowManager(self._AWSIoTMQTTClient._mqttClient)
69 |
70 | # Configuration APIs
71 | def configureLastWill(self, topic, payload, QoS):
72 | self._AWSIoTMQTTClient.configureLastWill(topic, payload, QoS)
73 |
74 | def clearLastWill(self):
75 | self._AWSIoTMQTTClient.clearLastWill()
76 |
77 | def configureEndpoint(self, hostName, portNumber):
78 | self._AWSIoTMQTTClient.configureEndpoint(hostName, portNumber)
79 |
80 | def configureIAMCredentials(self, AWSAccessKeyID, AWSSecretAccessKey, AWSSTSToken=""):
81 | # AWSIoTMQTTClient.configureIAMCredentials
82 | self._AWSIoTMQTTClient.configureIAMCredentials(AWSAccessKeyID, AWSSecretAccessKey, AWSSTSToken)
83 |
84 | def configureCredentials(self, CAFilePath, KeyPath="", CertificatePath=""): # Should be good for MutualAuth and Websocket
85 | self._AWSIoTMQTTClient.configureCredentials(CAFilePath, KeyPath, CertificatePath)
86 |
87 | def configureAutoReconnectBackoffTime(self, baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond):
88 | self._AWSIoTMQTTClient.configureAutoReconnectBackoffTime(baseReconnectQuietTimeSecond, maxReconnectQuietTimeSecond, stableConnectionTimeSecond)
89 |
90 | def configureConnectDisconnectTimeout(self, timeoutSecond):
91 | self._AWSIoTMQTTClient.configureConnectDisconnectTimeout(timeoutSecond)
92 |
93 | def configureMQTTOperationTimeout(self, timeoutSecond):
94 | self._AWSIoTMQTTClient.configureMQTTOperationTimeout(timeoutSecond)
95 |
96 | # Start the MQTT connection
97 | def connect(self, keepAliveIntervalSecond=30):
98 | return self._AWSIoTMQTTClient.connect(keepAliveIntervalSecond)
99 |
100 | # End the MQTT connection
101 | def disconnect(self):
102 | return self._AWSIoTMQTTClient.disconnect()
103 |
104 | # Shadow management API
105 | def createShadowHandlerWithName(self, shadowName, isPersistentSubscribe):
106 | # Create and return a deviceShadow instance
107 | return deviceShadow.deviceShadow(shadowName, isPersistentSubscribe, self._shadowManager)
108 | # Shadow APIs are accessible in deviceShadow instance":
109 | ###
110 | # deviceShadow.shadowGet
111 | # deviceShadow.shadowUpdate
112 | # deviceShadow.shadowDelete
113 | # deviceShadow.shadowRegisterDelta
114 | # deviceShadow.shadowUnregisterDelta
115 |
116 | # MQTT connection management API
117 | def getMQTTConnection(self):
118 | # Return the internal AWSIoTMQTTClient instance
119 | return self._AWSIoTMQTTClient
120 |
--------------------------------------------------------------------------------
/lib/mqtt_aws/MQTTShadowManager.py:
--------------------------------------------------------------------------------
1 | import _thread
2 | import time
3 |
4 | class shadowManager:
5 |
6 | def __init__(self, MQTTClient):
7 | if MQTTClient is None:
8 | raise ValueError("MQTT Client is none")
9 |
10 | self._mqttClient = MQTTClient
11 | self._subscribe_mutex = _thread.allocate_lock()
12 |
13 | def getClientID(self):
14 | return self._mqttClient.getClientID()
15 |
16 | def _getDeltaTopic(self, shadowName):
17 | return "$aws/things/" + str(shadowName) + "/shadow/update/delta"
18 |
19 | def _getNonDeltaTopics(self, shadowName, actionName):
20 | generalTopic = "$aws/things/" + str(shadowName) + "/shadow/" + str(actionName)
21 | acceptTopic = "$aws/things/" + str(shadowName) + "/shadow/" + str(actionName) + "/accepted"
22 | rejectTopic = "$aws/things/" + str(shadowName) + "/shadow/" + str(actionName) + "/rejected"
23 |
24 | return (generalTopic, acceptTopic, rejectTopic)
25 |
26 | def shadowPublish(self, shadowName, shadowAction, payload):
27 | (generalTopic, acceptTopic, rejectTopic) = self._getNonDeltaTopics(shadowName, shadowAction)
28 | self._mqttClient.publish(generalTopic, payload, 0, False)
29 |
30 | def shadowSubscribe(self, shadowName, shadowAction, callback):
31 | self._subscribe_mutex.acquire()
32 | if shadowAction == "delta":
33 | deltaTopic = self._getDeltaTopic(shadowName)
34 | self._mqttClient.subscribe(deltaTopic, 0, callback)
35 | else:
36 | (generalTopic, acceptTopic, rejectTopic) = self._getNonDeltaTopics(shadowName, shadowAction)
37 | self._mqttClient.subscribe(acceptTopic, 0, callback)
38 | self._mqttClient.subscribe(rejectTopic, 0, callback)
39 | time.sleep(2)
40 | self._subscribe_mutex.release()
41 |
42 | def shadowUnsubscribe(self, srcShadowName, srcShadowAction):
43 | self._subscribe_mutex.acquire()
44 | currentShadowAction = _shadowAction(srcShadowName, srcShadowAction)
45 | if shadowAction == "delta":
46 | deltaTopic = self._getDeltaTopic(shadowName)
47 | self._mqttClient.unsubscribe(deltaTopic)
48 | else:
49 | (generalTopic, acceptTopic, rejectTopic) = self._getNonDeltaTopics(shadowName, shadowAction)
50 | self._mqttClient.unsubscribe(acceptTopic)
51 | self._mqttClient.unsubscribe(rejectTopic)
52 | self._subscribe_mutex.release()
53 |
54 | def insertShadowCallback(self, callback, payload, status, token):
55 | self._mqttClient.insertShadowCallback(callback, payload, status, token)
56 |
--------------------------------------------------------------------------------
/lib/sqnsupgrade/sqnscodec.py:
--------------------------------------------------------------------------------
1 | # -*- python -*-
2 | #################################################################
3 | #
4 | # Module : CODEC
5 | # Purpose: Base encoders/decoders
6 | #
7 | #################################################################
8 | #
9 | # Copyright (c) 2011 SEQUANS Communications.
10 | # All rights reserved.
11 | #
12 | # This is confidential and proprietary source code of SEQUANS
13 | # Communications. The use of the present source code and all
14 | # its derived forms is exclusively governed by the restricted
15 | # terms and conditions set forth in the SEQUANS
16 | # Communications' EARLY ADOPTER AGREEMENT and/or LICENCE
17 | # AGREEMENT. The present source code and all its derived
18 | # forms can ONLY and EXCLUSIVELY be used with SEQUANS
19 | # Communications' products. The distribution/sale of the
20 | # present source code and all its derived forms is EXCLUSIVELY
21 | # RESERVED to regular LICENCE holder and otherwise STRICTLY
22 | # PROHIBITED.
23 | #
24 | #################################################################
25 | import struct, array
26 |
27 | LITTLE_ENDIAN = "<"
28 | NATIVE_ENDIAN = "="
29 | BIG_ENDIAN = ">"
30 |
31 | # -------------------------------------------------// Utility /__________________________________
32 | class encode:
33 | @staticmethod
34 | def u32 (value, endian = BIG_ENDIAN):
35 | return array.array("c", struct.pack(endian + "I", value))
36 |
37 | @staticmethod
38 | def s32 (value, endian = BIG_ENDIAN):
39 | if value < 0:
40 | value = 0x100000000 + value
41 | return encode.u32(value, endian)
42 |
43 | @staticmethod
44 | def u16 (value, endian = BIG_ENDIAN):
45 | return array.array("c", struct.pack(endian + "H", value))
46 |
47 | @staticmethod
48 | def u8 (value, endian = None):
49 | return array.array("c", chr(value))
50 |
51 | @staticmethod
52 | def string (value, endian = None):
53 | return array.array("c", value + "\x00")
54 |
55 | class decode:
56 | @staticmethod
57 | def u32 (value, endian = BIG_ENDIAN):
58 | return struct.unpack(endian + "I", value)[0]
59 |
60 | @staticmethod
61 | def s32 (value, endian = BIG_ENDIAN):
62 | v = decode.u32(value, endian)
63 | if v & (1 << 31):
64 | return v - 0x100000000
65 | return v
66 |
67 | @staticmethod
68 | def u16 (value, endian = BIG_ENDIAN):
69 | return struct.unpack(endian + "H", value)[0]
70 |
71 | @staticmethod
72 | def u8 (value, endian = None):
73 | return ord(value)
74 |
75 | @staticmethod
76 | def string (value, endian = None):
77 | offset = 0
78 | str = ""
79 | c = value[offset]
80 | while c != '\x00':
81 | offset += 1
82 | str += c
83 | c = value[offset]
84 |
85 | return str
86 |
87 |
--------------------------------------------------------------------------------
/lib/sqnsupgrade/sqnscrc.py:
--------------------------------------------------------------------------------
1 | # -*- python -*-
2 | #################################################################
3 | #
4 | # Module : CRC
5 | # Purpose: CRC calculation
6 | #
7 | #################################################################
8 | #
9 | # Copyright (c) 2011 SEQUANS Communications.
10 | # All rights reserved.
11 | #
12 | # This is confidential and proprietary source code of SEQUANS
13 | # Communications. The use of the present source code and all
14 | # its derived forms is exclusively governed by the restricted
15 | # terms and conditions set forth in the SEQUANS
16 | # Communications' EARLY ADOPTER AGREEMENT and/or LICENCE
17 | # AGREEMENT. The present source code and all its derived
18 | # forms can ONLY and EXCLUSIVELY be used with SEQUANS
19 | # Communications' products. The distribution/sale of the
20 | # present source code and all its derived forms is EXCLUSIVELY
21 | # RESERVED to regular LICENCE holder and otherwise STRICTLY
22 | # PROHIBITED.
23 | #
24 | #################################################################
25 | import sqnscodec as codec
26 |
27 | # -------------------------------------------------// Fletcher /_________________________________
28 | def fletcher32 (data):
29 | l = len(data)
30 |
31 | index = 0
32 | s1 = s2 = 0xFFFF
33 | while l > 1:
34 | qty = 720 if l > 720 else (l & ~1)
35 | l -= qty
36 |
37 | qty += index
38 | while index < qty:
39 | word = codec.decode.u16(data[index:index+2])
40 | s1 += word
41 | s2 += s1
42 |
43 | index += 2
44 |
45 | s1 = (s1 & 0xFFFF) + (s1 >> 16)
46 | s2 = (s2 & 0xFFFF) + (s2 >> 16)
47 |
48 | if (l & 1):
49 | s1 += ord(data[index]) << 8
50 | s2 += s1
51 |
52 | s1 = (s1 & 0xFFFF) + (s1 >> 16)
53 | s2 = (s2 & 0xFFFF) + (s2 >> 16)
54 |
55 | s1 = (s1 & 0xFFFF) + (s1 >> 16)
56 | s2 = (s2 & 0xFFFF) + (s2 >> 16)
57 |
58 | return (s2 << 16) | s1
59 |
--------------------------------------------------------------------------------
/license/Pycom CLA Apache v1.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/license/Pycom CLA Apache v1.pdf
--------------------------------------------------------------------------------
/license/Pycom FAQ v2.2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/license/Pycom FAQ v2.2.pdf
--------------------------------------------------------------------------------
/license/Pycom Licences v2.2.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/license/Pycom Licences v2.2.pdf
--------------------------------------------------------------------------------
/pycom-docker-fw-build/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:bionic
2 |
3 | RUN apt-get update && apt-get -y install wget git build-essential python python-serial && \
4 | mkdir /opt/frozen/ && cd /opt && \
5 | wget -q https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz && \
6 | tar -xzvf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz && \
7 | git clone --recursive https://github.com/pycom/pycom-esp-idf.git && \
8 | cd pycom-esp-idf && git submodule update --init && cd .. && \
9 | git clone --recursive https://github.com/pycom/pycom-micropython-sigfox.git
10 |
11 | ADD assets/build /usr/bin/build
12 |
--------------------------------------------------------------------------------
/pycom-docker-fw-build/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Tool for adding your MicroPython code frozen in the flash
4 |
5 | ### usage:
6 | ```
7 | sudo docker run -v `pwd`:/opt/frozen -it goinvent/pycom-fw build board-type your-project-version-code [micropython-sigfox-git-tag] [esp-idf-git-tag]
8 | ```
9 | where board in `WIPY LOPY SIPY GPY FIPY LOPY4` and your-project-version-code is a tag for output file: `LOPY4-your-project-version-code.tar.gz`
10 |
11 |
12 | ### example:
13 |
14 | If you have your MicroPython project in the current directory `.` just type:
15 |
16 | ```
17 | sudo docker run -v `pwd`:/opt/frozen -it goinvent/pycom-fw build LOPY4 myproject
18 | ```
19 | For building against a specific revision (ex:v1.20.0.rc0 idf_v3.1) you can use:
20 | ```
21 | sudo docker run -v `pwd`:/opt/frozen -it goinvent/pycom-fw build FIPY myproject v1.20.0.rc0 idf_v3.1
22 | ```
23 |
24 |
25 | ### note:
26 |
27 | The Frozen code implementation might not support sub-directories in MicroPython code.
28 |
29 | The Frozen code implementation does not support adding assets (ex: db files, json,)
30 |
31 | ### re-generate this goinvent/pycom-fw docker image:
32 |
33 | ```
34 | sudo docker build -t goinvent/pycom-fw .
35 | ```
36 |
--------------------------------------------------------------------------------
/pycom-docker-fw-build/assets/build:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | boards="WIPY LOPY SIPY GPY FIPY LOPY4"
4 |
5 | function usage() {
6 | echo "Usage:"
7 | echo " $0 board-type version-code [micropython-sigfox-git-tag] [esp-idf-git-tag]"
8 | echo ""
9 | echo "where board-type in $boards and version-code is a tag for output file"
10 | echo ""
11 | exit 1
12 | }
13 |
14 | function prepare_dev() {
15 | echo "Checkout $1 $2 board version-code"
16 |
17 | if [ ! -z "$1" ]
18 | then
19 | cd /opt/pycom-micropython-sigfox
20 | # fetch all branches
21 | git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
22 | # try to find branch revision $1
23 | if git pull ; git rev-list $1.. >/dev/null
24 |
25 | then
26 | echo "Checkout "
27 | else
28 | exit 1
29 | fi
30 | cd /opt/pycom-micropython-sigfox
31 | git checkout $1
32 | cd mpy-cross && make clean && make && cd ..
33 | git submodule update --init
34 | fi
35 |
36 | if [ ! -z "$2" ]
37 | then
38 | cd /opt/pycom-esp-idf;
39 | # fetch all branches
40 | git branch -r | grep -v '\->' | while read remote; do git branch --track "${remote#origin/}" "$remote"; done
41 | # try to find branch revision $2
42 | if git rev-list $2.. >/dev/null
43 |
44 | then
45 | echo ""
46 | # branch exists
47 | else
48 | # branch does not exists
49 | exit
50 | fi
51 | cd /opt/pycom-esp-idf
52 | git checkout $2
53 | git submodule update --init
54 | fi
55 | }
56 |
57 | function build() {
58 | BOARD=$1
59 | PROJECT=$2
60 | export PATH=$PATH:/opt/xtensa-esp32-elf/bin/
61 | export IDF_PATH=/opt/pycom-esp-idf
62 | board=`echo "$BOARD" | tr '[:upper:]' '[:lower:]'`
63 | cd /opt/pycom-micropython-sigfox/esp32/ &&
64 | make clean BOARD=$BOARD &&
65 | cd ../mpy-cross && make clean && make && cd ../esp32 &&
66 | cp /opt/frozen/*.py ./frozen/Base/ &&
67 | mv ./frozen/Base/main.py ./frozen/Base/_main.py
68 | make release BOARD=$BOARD RELEASE_DIR=/tmp
69 | mv /tmp/*.tar.gz /opt/frozen/$board-firmware-$PROJECT.tar.gz
70 | echo "Firmware $board-firmware-$PROJECT.tar.gz ready !"
71 | }
72 |
73 | [[ $boards =~ (^|[[:space:]])$1($|[[:space:]]) ]] &&
74 | echo "#goinvent " ||
75 | usage
76 | prepare_dev $3 $4
77 | build $1 $2
78 |
--------------------------------------------------------------------------------
/pymesh/mobile_app/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Pymesh mobile application
3 |
4 | For demonstrating **Pymesh** features, a mobile application was created.
5 |
6 | It is available for both Android and iOS platforms.
7 |
8 | ## Android application
9 |
10 | It is available as `.apk` packet in this directory.
11 |
12 | # iOS mobile application
13 |
14 | Pymesh mobile application is released currently (v0.) as Beta testing, on Apple TestFlight (to be installed for free from App Store).
15 |
16 | Pymesh app can be added afterwards, using the link: https://testflight.apple.com/join/PIxwbTKp
17 |
18 | Requirements: iOS minimum version v12.1
19 |
--------------------------------------------------------------------------------
/pymesh/mobile_app/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/pymesh/mobile_app/app-release.apk
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/README.md:
--------------------------------------------------------------------------------
1 | # Pymesh micropython code
2 |
3 | This project exemplifies the use of Pycom's proprietary LoRa Mesh network - **Pymesh**.
4 | These scripts were created and tested on Lopy4 and Fipy, using the Pymesh binary release.
5 |
6 | Official Pymesh docs: https://docs.pycom.io/pymesh/
7 |
8 | Forum Pymesh announcements: https://forum.pycom.io/topic/4449/pymesh-updates
9 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/copy_fw.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | #set -x
4 | SOURCE="$(dirname $0)"
5 | if [ -z $1 ]; then
6 | echo "usage: $0 micropython_firmware_directory"
7 | exit 1
8 | fi
9 | if [ ! -d $1/esp32/frozen/Common ]; then
10 | echo "Need to specify valid micropython firmware directory!"
11 | exit 1
12 | fi
13 | if [ ! -d $SOURCE ]; then
14 | echo "Can't find source directory $SOURCE"
15 | exit 1
16 | fi
17 |
18 | # moving main
19 | # if [ -d $1/esp32/frozen/Pybytes ]; then
20 | # cp $SOURCE/main.py $1/esp32/frozen/Pybytes/_main.py
21 | # cp $1/esp32/frozen/Base/_boot.py $1/esp32/frozen/Pybytes/
22 | # elif [ -d $1/esp32/frozen/Base ]; then
23 | # cp $SOURCE/main.py $1/esp32/frozen/Base/_main.py
24 | # else
25 | # cp $SOURCE/main.py $1/esp32/frozen/_main.py
26 | # fi
27 |
28 | for i in $SOURCE/lib/*.py; do
29 | SRC=$i
30 | FN=$(basename $i)
31 | cp $SRC $1/esp32/frozen/Common/_$FN
32 | done
33 |
34 | cp -r $SOURCE/lib/msgpack $1/esp32/frozen/Common/
35 | echo "Done copying Pymesh library to $1/esp32/frozen/Common/"
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/lib/ble_services.py:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2020, Pycom Limited.
2 | #
3 | # This software is licensed under the GNU GPL version 3 or any
4 | # later version, with permitted additional terms. For more information
5 | # see the Pycom Licence v1.0 document supplied with this file, or
6 | # available at https://www.pycom.io/opensource/licensing
7 |
8 | from network import Bluetooth
9 | import time
10 | import msgpack
11 |
12 | VERSION = "1.0.0"
13 |
14 | class BleServices:
15 |
16 | def __init__(self, ble_name):
17 | # self.mesh_mac = mesh_mac
18 | self.ble_name = ble_name
19 | self.on_disconnect = None
20 | self._init()
21 |
22 | def _init(self):
23 | self.status = {
24 | 'connected' : False
25 | }
26 |
27 | bluetooth = Bluetooth(modem_sleep=False)
28 | adv_name = self.ble_name
29 | bluetooth.set_advertisement(name=adv_name, service_uuid=0xec00)
30 | print("BLE name:", adv_name)
31 |
32 | bluetooth.callback(trigger=Bluetooth.CLIENT_CONNECTED | Bluetooth.CLIENT_DISCONNECTED, handler=self.conn_cb)
33 | bluetooth.advertise(True)
34 |
35 | srv_rx = bluetooth.service(uuid=0xec00, isprimary=True)
36 | self.chr_rx = srv_rx.characteristic(uuid=0xec0e, value=0)
37 |
38 | srv_tx = bluetooth.service(uuid=0xed00, isprimary=True)
39 | self.chr_tx = srv_tx.characteristic(uuid=0xed0e, value=0)
40 |
41 | self.unpacker = None
42 |
43 | def conn_cb(self, bt_o):
44 | #global ble_connected
45 | events = bt_o.events()
46 | if events & Bluetooth.CLIENT_CONNECTED:
47 | self.status['connected'] = True
48 | print("Client connected")
49 | elif events & Bluetooth.CLIENT_DISCONNECTED:
50 | self.status['connected'] = False
51 |
52 | if self.on_disconnect:
53 | self.on_disconnect()
54 |
55 | print("Client disconnected")
56 | pass
57 |
58 | def unpacker_set(self, unpacker):
59 | self.unpacker = unpacker
60 |
61 | def close(self):
62 | bluetooth = Bluetooth()
63 | bluetooth.disconnect_client()
64 | bluetooth.deinit()
65 | pass
66 |
67 | def restart(self):
68 | print("BLE disconnnect client")
69 | bluetooth = Bluetooth()
70 | bluetooth.disconnect_client()
71 | time.sleep(2)
72 | self.status['connected'] = False
73 | if self.on_disconnect:
74 | self.on_disconnect()
75 |
76 | # bluetooth.deinit()
77 | # time.sleep(1)
78 | # self._init()
79 | pass
80 |
81 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/lib/gps.py:
--------------------------------------------------------------------------------
1 |
2 | # Copyright (c) 2020, Pycom Limited.
3 | #
4 | # This software is licensed under the GNU GPL version 3 or any
5 | # later version, with permitted additional terms. For more information
6 | # see the Pycom Licence v1.0 document supplied with this file, or
7 | # available at https://www.pycom.io/opensource/licensing
8 |
9 | try:
10 | from pymesh_debug import print_debug
11 | except:
12 | from _pymesh_debug import print_debug
13 |
14 | import time
15 | # from pytrack import Pytrack
16 | # from L76GNSS import L76GNSS
17 | from machine import Timer
18 |
19 | __version__ = '1'
20 | """
21 | * initial version
22 | """
23 |
24 | class Gps:
25 | # Pycom office GPS coordinates
26 | lat = 51.45
27 | lon = 5.45313
28 |
29 | l76 = None
30 | _timer = None
31 | #is_set = False
32 |
33 | @staticmethod
34 | def set_location(latitude, longitude):
35 | dlat = str(type(latitude))
36 | dlon = str(type(longitude))
37 | if dlat == dlon == "":
38 | Gps.lat = latitude
39 | Gps.lon = longitude
40 | is_set = True
41 | else:
42 | print_debug(3, "Error parsing ", latitude, longitude)
43 |
44 | @staticmethod
45 | def get_location():
46 | return (Gps.lat, Gps.lon)
47 |
48 | # @staticmethod
49 | # def init_static():
50 | # is_pytrack = True
51 | # try:
52 | # py = Pytrack()
53 | # Gps.l76 = L76GNSS(py, timeout=30)
54 | # #l76.coordinates()
55 | # Gps._timer = Timer.Alarm(Gps.gps_periodic, 30, periodic=True)
56 | # print_debug(3, "Pytrack detected")
57 | # except:
58 | # is_pytrack = False
59 | # print_debug(3, "Pytrack NOT detected")
60 | # #TODO: how to check if GPS is conencted
61 | # return is_pytrack
62 |
63 | # @staticmethod
64 | # def gps_periodic(alarm):
65 | # t0 = time.ticks_ms()
66 | # coord = Gps.l76.coordinates()
67 | # if coord[0] != None:
68 | # Gps.lat, Gps.lon = coord
69 | # print_debug(3, "New coord ", coord)
70 | # dt = time.ticks_ms() - t0
71 | # print_debug(3, " =====>>>> gps_periodic ", dt)
72 |
73 | # @staticmethod
74 | # def terminate():
75 | # if Gps._timer is not None:
76 | # Gps._timer.cancel()
77 | # pass
78 |
79 | """
80 | from pytrack import Pytrack
81 | from L76GNSS import L76GNSS
82 | py = Pytrack()
83 | l76 = L76GNSS(py, timeout=30)
84 | t0 = time.ticks_ms()
85 | l76.coordinates()
86 | y = time.ticks_ms() - t0
87 | y
88 | """
89 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/lib/msgpack/__init__.py:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | from msgpack._version import version
3 | from msgpack.exceptions import *
4 |
5 | from ucollections import namedtuple
6 |
7 |
8 | class ExtType(namedtuple('ExtType', 'code data')):
9 | """ExtType represents ext type in msgpack."""
10 | def __new__(cls, code, data):
11 | if not isinstance(code, int):
12 | raise TypeError("code must be int")
13 | if not isinstance(data, bytes):
14 | raise TypeError("data must be bytes")
15 | if not 0 <= code <= 127:
16 | raise ValueError("code must be 0~127")
17 | return super(ExtType, cls).__new__(cls, code, data)
18 |
19 |
20 | import os
21 | from msgpack.fallback import Packer, unpackb, Unpacker
22 |
23 |
24 | def pack(o, stream, **kwargs):
25 | """
26 | Pack object `o` and write it to `stream`
27 |
28 | See :class:`Packer` for options.
29 | """
30 | packer = Packer(**kwargs)
31 | stream.write(packer.pack(o))
32 |
33 |
34 | def packb(o, **kwargs):
35 | """
36 | Pack object `o` and return packed bytes
37 |
38 | See :class:`Packer` for options.
39 | """
40 | return Packer(**kwargs).pack(o)
41 |
42 |
43 | def unpack(stream, **kwargs):
44 | """
45 | Unpack an object from `stream`.
46 |
47 | Raises `ExtraData` when `stream` contains extra bytes.
48 | See :class:`Unpacker` for options.
49 | """
50 | data = stream.read()
51 | return unpackb(data, **kwargs)
52 |
53 |
54 | # alias for compatibility to simplejson/marshal/pickle.
55 | load = unpack
56 | loads = unpackb
57 |
58 | dump = pack
59 | dumps = packb
60 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/lib/msgpack/_version.py:
--------------------------------------------------------------------------------
1 | version = (0, 5, 6)
2 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/lib/msgpack/exceptions.py:
--------------------------------------------------------------------------------
1 | class UnpackException(Exception):
2 | """Deprecated. Use Exception instead to catch all exception during unpacking."""
3 |
4 |
5 | class BufferFull(UnpackException):
6 | pass
7 |
8 |
9 | class OutOfData(UnpackException):
10 | pass
11 |
12 |
13 | class UnpackValueError(UnpackException):
14 | """Deprecated. Use ValueError instead."""
15 |
16 |
17 | class ExtraData(UnpackValueError):
18 | def __init__(self, unpacked, extra):
19 | self.unpacked = unpacked
20 | self.extra = extra
21 |
22 | def __str__(self):
23 | return "unpack(b) received extra data."
24 |
25 |
26 | class PackException(Exception):
27 | """Deprecated. Use Exception instead to catch all exception during packing."""
28 |
29 |
30 | class PackValueError(PackException):
31 | """PackValueError is raised when type of input data is supported but it's value is unsupported.
32 |
33 | Deprecated. Use ValueError instead.
34 | """
35 |
36 |
37 | class PackOverflowError(PackValueError):
38 | """PackOverflowError is raised when integer value is out of range of msgpack support [-2**31, 2**32).
39 |
40 | Deprecated. Use ValueError instead.
41 | """
42 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/lib/pymesh_config.py:
--------------------------------------------------------------------------------
1 | '''
2 | Copyright (c) 2020, Pycom Limited.
3 | This software is licensed under the GNU GPL version 3 or any
4 | later version, with permitted additional terms. For more information
5 | see the Pycom Licence v1.0 document supplied with this file, or
6 | available at https://www.pycom.io/opensource/licensing
7 | '''
8 | import json
9 |
10 | from network import LoRa
11 | import machine
12 | import time
13 |
14 | try:
15 | from pymesh_debug import print_debug
16 | except:
17 | from _pymesh_debug import print_debug
18 |
19 | __version__ = '2'
20 | """
21 | __version__ = '2'
22 | * added BR_ena, BR_prio
23 |
24 | __version__ = ''
25 | * first release
26 |
27 | """
28 |
29 | class PymeshConfig:
30 |
31 | CONFIG_FILENAME = "/flash/pymesh_config.json"
32 |
33 | ############################################################
34 | # DEFAULT SETTINGS
35 |
36 | # LoRa region is one of LoRa.US915, LoRa.EU868, LoRa.AS923, LoRa.AU915
37 | LORA_REGION = LoRa.EU868
38 |
39 | # frequency expressed in Hz, for EU868 863000000 Hz, for US915 904600000 Hz
40 | LORA_FREQ = const(869000000)
41 |
42 | # bandwidth options are: LoRa.BW_125KHZ, LoRa.BW_250KHZ or LoRa.BW_500KHZ
43 | LORA_BW = LoRa.BW_500KHZ
44 |
45 | # spreading factor options are 7 to 12
46 | LORA_SF = const(7)
47 |
48 | # Pymesh 128b key, used for auth. and encryption
49 | KEY = "112233"
50 |
51 | # if true, Pymesh is auto-started
52 | AUTOSTART = True
53 | DEBUG_LEVEL = 5
54 |
55 | # if true, it will start as BLE Server, to be connected with mobile app
56 | BLE_API = False
57 | BLE_NAME_PREFIX = "PyGo "
58 |
59 | ############################################################
60 | # Border router preference priority
61 | BR_PRIORITY_NORM = const(0)
62 | BR_PRIORITY_LOW = const(-1)
63 | BR_PRIORITY_HIGH = const(1)
64 |
65 | # if true then this node is Border Router
66 | BR_ENABLE = False
67 | # the default BR priority
68 | BR_PRIORITY = BR_PRIORITY_NORM
69 |
70 | def write_config(pymesh_config, force_restart = False):
71 | cf = open(PymeshConfig.CONFIG_FILENAME, 'w')
72 | cf.write(json.dumps(pymesh_config))
73 | cf.close()
74 |
75 | if force_restart:
76 | print_debug(3, "write_config force restart")
77 | time.sleep(1)
78 | machine.deepsleep(1000)
79 |
80 | def check_mac(pymesh_config, MAC):
81 | if pymesh_config.get('MAC') is None:
82 | # if MAC config unspecified, set it to LoRa MAC
83 | print_debug(3, "Set MAC in config file as " + str(MAC))
84 | pymesh_config['MAC'] = MAC
85 | PymeshConfig.write_config(pymesh_config, False)
86 | else:
87 | mac_from_config = pymesh_config.get('MAC')
88 | if mac_from_config != MAC:
89 | print_debug(3, "MAC different"+ str(mac_from_config) + str(MAC))
90 | pymesh_config['MAC'] = MAC
91 | # if MAC in config different than LoRa MAC, set LoRa MAC as in config file
92 | fo = open("/flash/sys/lpwan.mac", "wb")
93 | mac_write=bytes([(MAC >> 56) & 0xFF, (MAC >> 48) & 0xFF, (MAC >> 40) & 0xFF, (MAC >> 32) & 0xFF, (MAC >> 24) & 0xFF, (MAC >> 16) & 0xFF, (MAC >> 8) & 0xFF, MAC & 0xFF])
94 | fo.write(mac_write)
95 | fo.close()
96 | # print_debug(3, "reset")
97 | PymeshConfig.write_config(pymesh_config, False)
98 |
99 | print_debug(3, "MAC ok" + str(MAC))
100 |
101 | def read_config(MAC):
102 | file = PymeshConfig.CONFIG_FILENAME
103 | pymesh_config = {}
104 | error_file = True
105 |
106 | try:
107 | import json
108 | f = open(file, 'r')
109 | jfile = f.read()
110 | f.close()
111 | try:
112 | pymesh_config = json.loads(jfile.strip())
113 | # pymesh_config['cfg_msg'] = "Pymesh configuration read from {}".format(file)
114 | error_file = False
115 | except Exception as ex:
116 | print_debug(1, "Error reading {} file!\n Exception: {}".format(file, ex))
117 | except Exception as ex:
118 | print_debug(1, "Final error reading {} file!\n Exception: {}".format(file, ex))
119 |
120 | if error_file:
121 | # config file can't be read, so it needs to be created and saved
122 | pymesh_config = {}
123 | print_debug(3, "Can't find" +str(file) + ", or can't be parsed as json; Set default settings and reset")
124 | # don't write MAC, just to use the hardware one
125 | pymesh_config['LoRa'] = {"region": PymeshConfig.LORA_REGION,
126 | "freq": PymeshConfig.LORA_FREQ,
127 | "bandwidth": PymeshConfig.LORA_BW,
128 | "sf": PymeshConfig.LORA_SF}
129 | pymesh_config['Pymesh'] = {"key": PymeshConfig.KEY}
130 | pymesh_config['autostart'] = PymeshConfig.AUTOSTART
131 | pymesh_config['debug'] = PymeshConfig.DEBUG_LEVEL
132 | pymesh_config['ble_api'] = PymeshConfig.BLE_API
133 | pymesh_config['ble_name_prefix'] = PymeshConfig.BLE_NAME_PREFIX
134 | pymesh_config['br_ena'] = PymeshConfig.BR_ENABLE
135 | pymesh_config['br_prio'] = PymeshConfig.BR_PRIORITY
136 |
137 | PymeshConfig.check_mac(pymesh_config, MAC)
138 | print_debug(3, "Default settings:" + str(pymesh_config))
139 | PymeshConfig.write_config(pymesh_config, True)
140 |
141 | PymeshConfig.check_mac(pymesh_config, MAC)
142 | print_debug(3, "Settings:" + str(pymesh_config))
143 | return pymesh_config
144 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/lib/pymesh_debug.py:
--------------------------------------------------------------------------------
1 |
2 | # Copyright (c) 2020, Pycom Limited.
3 | #
4 | # This software is licensed under the GNU GPL version 3 or any
5 | # later version, with permitted additional terms. For more information
6 | # see the Pycom Licence v1.0 document supplied with this file, or
7 | # available at https://www.pycom.io/opensource/licensing
8 |
9 | import pycom
10 |
11 | # recommended debug levels, from the most verbose to off
12 | DEBUG_DEBG = const(5)
13 | DEBUG_INFO = const(4)
14 | DEBUG_NOTE = const(3)
15 | DEBUG_WARN = const(2)
16 | DEBUG_CRIT = const(1)
17 | DEBUG_NONE = const(0)
18 |
19 | try:
20 | DEBUG = pycom.nvs_get('pymesh_debug')
21 | except:
22 | DEBUG = None
23 |
24 |
25 | def print_debug(level, msg):
26 | """Print log messages into console."""
27 | if DEBUG is not None and level <= DEBUG:
28 | print(msg)
29 |
30 | def debug_level(level):
31 | global DEBUG
32 | if level is None:
33 | try:
34 | ret = pycom.nvs_get('pymesh_debug')
35 | except:
36 | ret = None
37 | return ret
38 | try:
39 | ret = int(level)
40 | except:
41 | return
42 |
43 | DEBUG = ret
44 | pycom.nvs_set('pymesh_debug', DEBUG)
45 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/lorawan/lorawan.py:
--------------------------------------------------------------------------------
1 | """ OTAA Node example compatible with the LoPy Nano Gateway """
2 |
3 | from network import LoRa
4 | from network import WLAN
5 | import socket
6 | import binascii
7 | import struct
8 | import time
9 | from machine import RTC
10 |
11 | class Lorawan:
12 |
13 | def __init__(self):
14 | # create an OTA authentication params
15 | self.dev_eui = binascii.unhexlify('007926C9EAE4C922')
16 | self.app_eui = binascii.unhexlify('70B3D57ED001D8C8')
17 | self.app_key = binascii.unhexlify('2C4D6AE9CEBA8B0EB4430C33C17750CB')
18 |
19 | def send(self):
20 | t0 = time.time()
21 | print("LoRaWAN start")
22 | lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868)
23 |
24 | # set the 3 default channels to the same frequency (must be before sending the OTAA join request)
25 | lora.add_channel(0, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
26 | lora.add_channel(1, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
27 | lora.add_channel(2, frequency=config.LORA_FREQUENCY, dr_min=0, dr_max=5)
28 |
29 | # join a network using OTAA
30 | lora.join(activation=LoRa.OTAA, auth=(self.dev_eui, self.app_eui, self.app_key), timeout=0, dr=config.LORA_NODE_DR)
31 |
32 | # wait until the module has joined the network
33 | while not lora.has_joined():
34 | time.sleep(2.5)
35 | print('Not joined yet...', time.localtime())
36 |
37 | # remove all the non-default channels
38 | for i in range(3, 16):
39 | lora.remove_channel(i)
40 |
41 | # create a LoRa socket
42 | s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
43 |
44 | # set the LoRaWAN data rate
45 | s.setsockopt(socket.SOL_LORA, socket.SO_DR, config.LORA_NODE_DR)
46 |
47 | # make the socket non-blocking
48 | s.setblocking(False)
49 |
50 | pkt = b'PKT #' + bytes([i])
51 | print('Sending:', pkt)
52 | s.send(pkt)
53 | print("LoRaWAN done in ", time.time() - t0, " seconds")
54 |
55 | class config:
56 | # for EU868
57 | LORA_FREQUENCY = 867500000
58 | LORA_GW_DR = "SF7BW125" # DR_5
59 | LORA_NODE_DR = 5
60 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/lorawan/main.py:
--------------------------------------------------------------------------------
1 | import time
2 | import ubinascii
3 | import pycom
4 | from network import LoRa
5 |
6 | try:
7 | from pymesh_config import PymeshConfig
8 | except:
9 | from _pymesh_config import PymeshConfig
10 |
11 | try:
12 | from pymesh import Pymesh
13 | except:
14 | from _pymesh import Pymesh
15 |
16 | def new_message_cb(rcv_ip, rcv_port, rcv_data):
17 | ''' callback triggered when a new packet arrived '''
18 | print('Incoming %d bytes from %s (port %d):' %
19 | (len(rcv_data), rcv_ip, rcv_port))
20 | print(rcv_data)
21 |
22 | # user code to be inserted, to send packet to the designated Mesh-external interface
23 | for _ in range(3):
24 | pycom.rgbled(0x888888)
25 | time.sleep(.2)
26 | pycom.rgbled(0)
27 | time.sleep(.1)
28 | return
29 |
30 |
31 | pycom.heartbeat(False)
32 |
33 | lora = LoRa(mode=LoRa.LORA, region= LoRa.EU868)
34 | lora_mac = int(str(ubinascii.hexlify(lora.mac()))[2:-1], 16)
35 |
36 | # read config file, or set default values
37 | pymesh_config = PymeshConfig.read_config(lora_mac)
38 |
39 | #initialize Pymesh
40 | pymesh = Pymesh(pymesh_config, new_message_cb)
41 |
42 | while not pymesh.is_connected():
43 | print(pymesh.status_str())
44 | time.sleep(3)
45 |
46 | # send message to the Node having MAC address 5
47 | pymesh.send_mess(20, "Hello World")
48 |
49 | print("done Pymesh init, forever loop, exit/stop with Ctrl+C multiple times")
50 |
51 | from lorawan import Lorawan
52 | lorawan = Lorawan()
53 | t0 = time.time()
54 |
55 | while True:
56 | if time.time() - t0 > 60:
57 | pymesh.pause()
58 |
59 | lorawan.send()
60 |
61 | pymesh.resume()
62 | t0 = time.time()
63 | if time.time() - t0 > 35:
64 | pymesh.send_mess(20, "heloo again, #22 here, " + str(time.time()))
65 |
66 | time.sleep(5)
67 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/main-pybytes.py:
--------------------------------------------------------------------------------
1 | import time
2 | import pycom
3 |
4 | # todo: add try/except for checking pybytes object exists
5 | pymesh = pybytes.__pymesh.__pymesh
6 |
7 | print("Set maximum debug level, disable debug using pymesh.debug_level(0)")
8 | pymesh.debug_level(5)
9 |
10 | while not pymesh.is_connected():
11 | print(pymesh.status_str())
12 | time.sleep(3)
13 |
14 | print(pymesh.status_str())
15 | # send message to the Node having MAC address 5
16 | pymesh.send_mess(18, "Hello World")
17 |
18 | print("done Pymesh init, CLI is started, h - help/command list, stop - CLI will be stopped")
19 | pymesh.cli_start()
20 |
21 | # send a packet to Pybytes, thru the BR (if any enabled)
22 | # pybytes.send_signal(100, "Hello from device" + str(pymesh.mac()))
23 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/main.py:
--------------------------------------------------------------------------------
1 | import time
2 | import ubinascii
3 | import pycom
4 | from network import LoRa
5 |
6 | try:
7 | from pymesh_config import PymeshConfig
8 | except:
9 | from _pymesh_config import PymeshConfig
10 |
11 | try:
12 | from pymesh import Pymesh
13 | except:
14 | from _pymesh import Pymesh
15 |
16 | def new_message_cb(rcv_ip, rcv_port, rcv_data):
17 | ''' callback triggered when a new packet arrived '''
18 | print('Incoming %d bytes from %s (port %d):' %
19 | (len(rcv_data), rcv_ip, rcv_port))
20 | print(rcv_data)
21 |
22 | # user code to be inserted, to send packet to the designated Mesh-external interface
23 | for _ in range(3):
24 | pycom.rgbled(0x888888)
25 | time.sleep(.2)
26 | pycom.rgbled(0)
27 | time.sleep(.1)
28 | return
29 |
30 |
31 | pycom.heartbeat(False)
32 |
33 | lora = LoRa(mode=LoRa.LORA, region= LoRa.EU868)
34 | lora_mac = int(str(ubinascii.hexlify(lora.mac()))[2:-1], 16)
35 |
36 | # read config file, or set default values
37 | pymesh_config = PymeshConfig.read_config(lora_mac)
38 |
39 | #initialize Pymesh
40 | pymesh = Pymesh(pymesh_config, new_message_cb)
41 |
42 | # mac = pymesh.mac()
43 | # if mac > 10:
44 | # pymesh.end_device(True)
45 | # elif mac == 5:
46 | # pymesh.leader_priority(255)
47 |
48 | while not pymesh.is_connected():
49 | print(pymesh.status_str())
50 | time.sleep(3)
51 |
52 | # send message to the Node having MAC address 5
53 | pymesh.send_mess(5, "Hello World")
54 |
55 | # def new_br_message_cb(rcv_ip, rcv_port, rcv_data, dest_ip, dest_port):
56 | # ''' callback triggered when a new packet arrived for the current Border Router,
57 | # having destination an IP which is external from Mesh '''
58 | # print('Incoming %d bytes from %s (port %d), to external IPv6 %s (port %d)' %
59 | # (len(rcv_data), rcv_ip, rcv_port, dest_ip, dest_port))
60 | # print(rcv_data)
61 |
62 | # # user code to be inserted, to send packet to the designated Mesh-external interface
63 | # # ...
64 | # return
65 |
66 | # add current node as Border Router, with a priority and a message handler callback
67 | # pymesh.br_set(PymeshConfig.BR_PRIORITY_NORM, new_br_message_cb)
68 |
69 | # remove Border Router function from current node
70 | # pymesh.br_remove()
71 |
72 | # send data for Mesh-external, basically to the BR
73 | # ip = "1:2:3::4"
74 | # port = 5555
75 | # pymesh.send_mess_external(ip, port, "Hello World")
76 |
77 | print("done Pymesh init, CLI is started, h - help/command list, stop - CLI will be stopped")
78 | pymesh.cli_start()
79 |
80 | # while True:
81 | # time.sleep(3)
82 |
--------------------------------------------------------------------------------
/pymesh/pymesh_frozen/main_BR.py:
--------------------------------------------------------------------------------
1 | import time
2 | import ubinascii
3 | import pycom
4 | from network import LoRa
5 |
6 | # 2 = test pybytes OTA feature
7 | # 4 = added device_id (pybytes token) in the packets to BR
8 | __VERSION__ = 4
9 |
10 | try:
11 | from pymesh_config import PymeshConfig
12 | except:
13 | from _pymesh_config import PymeshConfig
14 |
15 | try:
16 | from pymesh import Pymesh
17 | except:
18 | from _pymesh import Pymesh
19 |
20 | PACK_TOCKEN_PREFIX = "tkn"
21 | PACK_TOCKEN_SEP = "#"
22 |
23 | print("Scripts version ", __VERSION__)
24 |
25 | if 'pybytes' not in globals():
26 | pybytes = None
27 |
28 | def new_message_cb(rcv_ip, rcv_port, rcv_data):
29 | ''' callback triggered when a new packet arrived '''
30 | print('Incoming %d bytes from %s (port %d):' %
31 | (len(rcv_data), rcv_ip, rcv_port))
32 | print(rcv_data)
33 |
34 | # user code to be inserted, to send packet to the designated Mesh-external interface
35 | for _ in range(3):
36 | pycom.rgbled(0x888888)
37 | time.sleep(.2)
38 | pycom.rgbled(0)
39 | time.sleep(.1)
40 | return
41 |
42 | def new_br_message_cb(rcv_ip, rcv_port, rcv_data, dest_ip, dest_port):
43 | ''' callback triggered when a new packet arrived for the current Border Router,
44 | having destination an IP which is external from Mesh '''
45 | print('Incoming %d bytes from %s (port %d), to external IPv6 %s (port %d)' %
46 | (len(rcv_data), rcv_ip, rcv_port, dest_ip, dest_port))
47 | print(rcv_data)
48 |
49 | for _ in range(2):
50 | pycom.rgbled(0x0)
51 | time.sleep(.1)
52 | # pycom.rgbled(0x001010)
53 | pycom.rgbled(0x663300)
54 | # time.sleep(.2)
55 |
56 | if pybytes is not None and pybytes.isconnected():
57 | # try to find Pybytes Token if include in rcv_data
58 | token = ""
59 | if rcv_data.startswith(PACK_TOCKEN_PREFIX):
60 | x = rcv_data.split(PACK_TOCKEN_SEP.encode())
61 | if len(x)>2:
62 | token = x[1]
63 | rcv_data = rcv_data[len(PACK_TOCKEN_PREFIX) + len(token) + len(PACK_TOCKEN_SEP):]
64 | pkt = 'BR %d B from %s (%s), to %s ( %d): %s'%(len(rcv_data), token, rcv_ip, dest_ip, dest_port, str(rcv_data))
65 | pybytes.send_signal(1, pkt)
66 |
67 | return
68 |
69 | pycom.heartbeat(False)
70 |
71 | lora = LoRa(mode=LoRa.LORA, region= LoRa.EU868)
72 | lora_mac = int(str(ubinascii.hexlify(lora.mac()))[2:-1], 16)
73 |
74 | # read config file, or set default values
75 | pymesh_config = PymeshConfig.read_config(lora_mac)
76 |
77 | #initialize Pymesh
78 | pymesh = Pymesh(pymesh_config, new_message_cb)
79 |
80 | # mac = pymesh.mac()
81 | # if mac > 10:
82 | # pymesh.end_device(True)
83 | # elif mac == 5:
84 | # pymesh.leader_priority(255)
85 |
86 | while not pymesh.is_connected():
87 | print(pymesh.status_str())
88 | time.sleep(3)
89 |
90 | # send message to the Node having MAC address 5
91 | pymesh.send_mess(2, "Hello World")
92 |
93 |
94 | print("done Pymesh init, forever loop, exit/stop with Ctrl+C multiple times")
95 | # set BR with callback
96 | if pybytes is not None and pybytes.isconnected():
97 | pybytes.send_signal(1, "RESTART")
98 |
99 | pyb_port = pymesh.mac() & 0xFFFF
100 | pyb_ip = '1:2:3::' + hex(pyb_port)[2:]
101 | pkt_start = ""
102 | # add pybytes token
103 | if pybytes is not None:
104 | pyb_dev_id = pybytes.get_config().get("device_id", "None")
105 | pkt_start = PACK_TOCKEN_PREFIX + PACK_TOCKEN_SEP + pyb_dev_id + PACK_TOCKEN_SEP
106 | pkt_start = pkt_start + "Hello, from " + str(pymesh.mac()) + ", time "
107 |
108 |
109 | br_enabled = False
110 |
111 | while True:
112 | # add current node as Border Router, with a priority and a message handler callback
113 |
114 | free_mem = pycom.get_free_heap()
115 |
116 | if pymesh_config.get("br_ena", False):
117 | if pybytes is not None and pybytes.isconnected():
118 | if not br_enabled:
119 | br_enabled = True
120 | print("Set as BR")
121 | pymesh.br_set(PymeshConfig.BR_PRIORITY_NORM, new_br_message_cb)
122 |
123 | pybytes.send_signal(1, str(pymesh.mac()) +" : " + str(time.time()) + "s, "+ str(free_mem))
124 | print("Send to Pyb,", free_mem)
125 | else: # not connected anymore to pybytes
126 | if br_enabled:
127 | br_enabled = False
128 | print("Remove as BR")
129 | pymesh.br_remove()
130 | else: # not MAC_BR
131 | pkt = pkt_start + str(time.time()) + ", mem " + str(free_mem)
132 | pymesh.send_mess_external(pyb_ip, pyb_port, pkt)
133 | print("Sending to BR: ", pkt)
134 |
135 | time.sleep(20)
136 |
--------------------------------------------------------------------------------
/pymesh/readme.md:
--------------------------------------------------------------------------------
1 | # For reference only
2 |
3 | This library is the open-source part of the Pymesh LoRa Firmware which can be provisioned through Pybytes and cannot be used as stand-alone on a Pybytes or Pygate type firmware. Please check the [Pycom Documentation](https://docs.pycom.io/pybytes/pymeshintegration/provisioning/) on how to get Pymesh type firmware provisioned to your device. You will not have to use this library in your project or flash it to your device separately, as it is already included in the firmware.
4 |
--------------------------------------------------------------------------------
/shields/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Pytrack, Pysense and Pyscan libraries
4 |
5 | ## Introduction
6 | This directory contains libraries and out of the box examples for Pysense, Pytrack, and Pyscan, both versions 1 and 2.0x of these shields.
7 |
8 | 1. Upload all the files to your module
9 | 2. Open Pymakr
10 | 3. Run an example that matches to your shield
11 |
12 | Note: For using Pyscan, you need to upload either MFRC630.mpy or MFRC630.py.
13 | It is always recommended to use MFRC630.mpy as it takes less space on your module.
14 |
--------------------------------------------------------------------------------
/shields/lib/L76GNSS.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | from machine import Timer
12 | import time
13 | import gc
14 | import binascii
15 |
16 |
17 | class L76GNSS:
18 |
19 | GPS_I2CADDR = const(0x10)
20 |
21 | def __init__(self, pytrack=None, sda='P22', scl='P21', timeout=None, buffer=64):
22 | if pytrack is not None:
23 | self.i2c = pytrack.i2c
24 | else:
25 | from machine import I2C
26 | self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
27 |
28 | self.chrono = Timer.Chrono()
29 |
30 | self.timeout = timeout
31 | self.timeout_status = True
32 | self.buffer = buffer
33 |
34 | self.reg = bytearray(1)
35 | self.i2c.writeto(GPS_I2CADDR, self.reg)
36 |
37 | def _read(self):
38 | self.reg = self.i2c.readfrom(GPS_I2CADDR, self.buffer)
39 | return self.reg
40 |
41 | def _convert_coords(self, gngll_s):
42 | lat = gngll_s[1]
43 | lat_d = (float(lat) // 100) + ((float(lat) % 100) / 60)
44 | lon = gngll_s[3]
45 | lon_d = (float(lon) // 100) + ((float(lon) % 100) / 60)
46 | if gngll_s[2] == 'S':
47 | lat_d *= -1
48 | if gngll_s[4] == 'W':
49 | lon_d *= -1
50 | return(lat_d, lon_d)
51 |
52 | def coordinates(self, debug=False):
53 | lat_d, lon_d, debug_timeout = None, None, False
54 | if self.timeout is not None:
55 | self.chrono.reset()
56 | self.chrono.start()
57 | nmea = b''
58 | while True:
59 | if self.timeout is not None and self.chrono.read() >= self.timeout:
60 | self.chrono.stop()
61 | chrono_timeout = self.chrono.read()
62 | self.chrono.reset()
63 | self.timeout_status = False
64 | debug_timeout = True
65 | if not self.timeout_status:
66 | gc.collect()
67 | break
68 | nmea += self._read().lstrip(b'\n\n').rstrip(b'\n\n')
69 | gngll_idx = nmea.find(b'GNGLL')
70 | gpgll_idx = nmea.find(b'GPGLL')
71 | if gngll_idx < 0 and gpgll_idx >= 0:
72 | gngll_idx = gpgll_idx
73 | if gngll_idx >= 0:
74 | gngll = nmea[gngll_idx:]
75 | e_idx = gngll.find(b'\r\n')
76 | if e_idx >= 0:
77 | try:
78 | gngll = gngll[:e_idx].decode('ascii')
79 | gngll_s = gngll.split(',')
80 | lat_d, lon_d = self._convert_coords(gngll_s)
81 | except Exception:
82 | pass
83 | finally:
84 | nmea = nmea[(gngll_idx + e_idx):]
85 | gc.collect()
86 | break
87 | else:
88 | gc.collect()
89 | if len(nmea) > 410: # i suppose it can be safely changed to 82, which is longest NMEA frame
90 | nmea = nmea[-5:] # $GNGL without last L
91 | time.sleep(0.1)
92 | self.timeout_status = True
93 | if debug and debug_timeout:
94 | print('GPS timed out after %f seconds' % (chrono_timeout))
95 | return(None, None)
96 | else:
97 | return(lat_d, lon_d)
98 |
99 | def dump_nmea(self):
100 | nmea = b''
101 | while True:
102 | nmea = self._read().lstrip(b'\n\n').rstrip(b'\n\n')
103 | start_idx = nmea.find(b'$')
104 | #print('raw[{}]: {}'.format(start_idx, nmea))
105 | if nmea is not None and len(nmea) > 0:
106 | if start_idx != 0:
107 | if len(nmea[:start_idx]) > 1:
108 | print('{}'.format(nmea[:start_idx].decode('ASCII')), end='')
109 | if len(nmea[start_idx:]) > 1:
110 | print('{}'.format(nmea[start_idx:].decode('ASCII')), end='')
111 |
112 | def _checksum(self, nmeadata):
113 | calc_cksum = 0
114 | for s in nmeadata:
115 | calc_cksum ^= ord(s)
116 | return('{:02X}'.format(calc_cksum))
117 |
118 | def write(self, data):
119 | self.i2c.writeto(GPS_I2CADDR, '${}*{}\r\n'.format(data, self._checksum(data)) )
120 |
--------------------------------------------------------------------------------
/shields/lib/LIS2HH12.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import math
12 | import time
13 | import struct
14 | from machine import Pin
15 |
16 |
17 | FULL_SCALE_2G = const(0)
18 | FULL_SCALE_4G = const(2)
19 | FULL_SCALE_8G = const(3)
20 |
21 | ODR_POWER_DOWN = const(0)
22 | ODR_10_HZ = const(1)
23 | ODR_50_HZ = const(2)
24 | ODR_100_HZ = const(3)
25 | ODR_200_HZ = const(4)
26 | ODR_400_HZ = const(5)
27 | ODR_800_HZ = const(6)
28 |
29 | ACC_G_DIV = 1000 * 65536
30 |
31 |
32 | class LIS2HH12:
33 |
34 | ACC_I2CADDR = const(30)
35 |
36 | PRODUCTID_REG = const(0x0F)
37 | CTRL1_REG = const(0x20)
38 | CTRL2_REG = const(0x21)
39 | CTRL3_REG = const(0x22)
40 | CTRL4_REG = const(0x23)
41 | CTRL5_REG = const(0x24)
42 | ACC_X_L_REG = const(0x28)
43 | ACC_X_H_REG = const(0x29)
44 | ACC_Y_L_REG = const(0x2A)
45 | ACC_Y_H_REG = const(0x2B)
46 | ACC_Z_L_REG = const(0x2C)
47 | ACC_Z_H_REG = const(0x2D)
48 | ACT_THS = const(0x1E)
49 | ACT_DUR = const(0x1F)
50 |
51 | SCALES = {FULL_SCALE_2G: 4000, FULL_SCALE_4G: 8000, FULL_SCALE_8G: 16000}
52 | ODRS = [0, 10, 50, 100, 200, 400, 800]
53 |
54 | def __init__(self, pysense = None, sda = 'P22', scl = 'P21'):
55 | if pysense is not None:
56 | self.i2c = pysense.i2c
57 | else:
58 | from machine import I2C
59 | self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
60 |
61 | self.odr = 0
62 | self.full_scale = 0
63 | self.x = 0
64 | self.y = 0
65 | self.z = 0
66 | self.int_pin = None
67 | self.act_dur = 0
68 | self.debounced = False
69 |
70 | whoami = self.i2c.readfrom_mem(ACC_I2CADDR , PRODUCTID_REG, 1)
71 | if (whoami[0] != 0x41):
72 | raise ValueError("LIS2HH12 not found")
73 |
74 | # enable acceleration readings at 50Hz
75 | self.set_odr(ODR_50_HZ)
76 |
77 | # change the full-scale to 4g
78 | self.set_full_scale(FULL_SCALE_4G)
79 |
80 | # set the interrupt pin as active low and open drain
81 | self.set_register(CTRL5_REG, 3, 0, 3)
82 |
83 | # make a first read
84 | self.acceleration()
85 |
86 | def acceleration(self):
87 | x = self.i2c.readfrom_mem(ACC_I2CADDR , ACC_X_L_REG, 2)
88 | self.x = struct.unpack(' self.SCALES[self.full_scale]:
128 | error = "threshold %d exceeds full scale %d" % (threshold, self.SCALES[self.full_scale])
129 | print(error)
130 | raise ValueError(error)
131 |
132 | if threshold < self.SCALES[self.full_scale] / 128:
133 | error = "threshold %d below resolution %d" % (threshold, self.SCALES[self.full_scale]/128)
134 | print(error)
135 | raise ValueError(error)
136 |
137 | if duration > 255 * 1000 * 8 / self.ODRS[self.odr]:
138 | error = "duration %d exceeds max possible value %d" % (duration, 255 * 1000 * 8 / self.ODRS[self.odr])
139 | print(error)
140 | raise ValueError(error)
141 |
142 | if duration < 1000 * 8 / self.ODRS[self.odr]:
143 | error = "duration %d below resolution %d" % (duration, 1000 * 8 / self.ODRS[self.odr])
144 | print(error)
145 | raise ValueError(error)
146 |
147 | _ths = int(127 * threshold / self.SCALES[self.full_scale]) & 0x7F
148 | _dur = int((duration * self.ODRS[self.odr]) / 1000 / 8)
149 |
150 | self.i2c.writeto_mem(ACC_I2CADDR, ACT_THS, _ths)
151 | self.i2c.writeto_mem(ACC_I2CADDR, ACT_DUR, _dur)
152 |
153 | # enable the activity/inactivity interrupt
154 | self.set_register(CTRL3_REG, 1, 5, 1)
155 |
156 | self._user_handler = handler
157 | self.int_pin = Pin('P13', mode=Pin.IN)
158 | self.int_pin.callback(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._int_handler)
159 |
160 | # return actual used threshold and duration
161 | return (_ths * self.SCALES[self.full_scale] / 128, _dur * 8 * 1000 / self.ODRS[self.odr])
162 |
163 | def activity(self):
164 | if not self.debounced:
165 | time.sleep_ms(self.act_dur)
166 | self.debounced = True
167 | if self.int_pin():
168 | return True
169 | return False
170 |
171 | def _int_handler(self, pin_o):
172 | if self._user_handler is not None:
173 | self._user_handler(pin_o)
174 | else:
175 | if pin_o():
176 | print('Activity interrupt')
177 | else:
178 | print('Inactivity interrupt')
179 |
--------------------------------------------------------------------------------
/shields/lib/LTR329ALS01.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import time
12 | from machine import I2C
13 |
14 | class LTR329ALS01:
15 | ALS_I2CADDR = const(0x29) # The device's I2C address
16 |
17 | ALS_CONTR_REG = const(0x80)
18 | ALS_MEAS_RATE_REG = const(0x85)
19 |
20 | ALS_DATA_CH1_LOW = const(0x88)
21 | ALS_DATA_CH1_HIGH = const(0x89)
22 | ALS_DATA_CH0_LOW = const(0x8A)
23 | ALS_DATA_CH0_HIGH = const(0x8B)
24 |
25 | ALS_GAIN_1X = const(0x00)
26 | ALS_GAIN_2X = const(0x01)
27 | ALS_GAIN_4X = const(0x02)
28 | ALS_GAIN_8X = const(0x03)
29 | ALS_GAIN_48X = const(0x06)
30 | ALS_GAIN_96X = const(0x07)
31 | ALS_GAIN_VALUES = {
32 | ALS_GAIN_1X: 1,
33 | ALS_GAIN_2X: 2,
34 | ALS_GAIN_4X: 4,
35 | ALS_GAIN_8X: 8,
36 | ALS_GAIN_48X: 48,
37 | ALS_GAIN_96X: 96
38 | }
39 |
40 | ALS_INT_50 = const(0x01)
41 | ALS_INT_100 = const(0x00)
42 | ALS_INT_150 = const(0x04)
43 | ALS_INT_200 = const(0x02)
44 | ALS_INT_250 = const(0x05)
45 | ALS_INT_300 = const(0x06)
46 | ALS_INT_350 = const(0x07)
47 | ALS_INT_400 = const(0x03)
48 | ALS_INT_VALUES = {
49 | ALS_INT_50: 0.5,
50 | ALS_INT_100: 1,
51 | ALS_INT_150: 1.5,
52 | ALS_INT_200: 2,
53 | ALS_INT_250: 2.5,
54 | ALS_INT_300: 3,
55 | ALS_INT_350: 3.5,
56 | ALS_INT_400: 4
57 | }
58 |
59 | ALS_RATE_50 = const(0x00)
60 | ALS_RATE_100 = const(0x01)
61 | ALS_RATE_200 = const(0x02)
62 | ALS_RATE_500 = const(0x03)
63 | ALS_RATE_1000 = const(0x04)
64 | ALS_RATE_2000 = const(0x05)
65 |
66 | def __init__(self, pysense = None, sda = 'P22', scl = 'P21', gain = ALS_GAIN_1X, integration = ALS_INT_100, rate = ALS_RATE_500):
67 | if pysense is not None:
68 | self.i2c = pysense.i2c
69 | else:
70 | self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
71 |
72 | self.gain = gain
73 | self.integration = integration
74 |
75 | contr = self._getContr(gain)
76 | self.i2c.writeto_mem(ALS_I2CADDR, ALS_CONTR_REG, bytearray([contr]))
77 |
78 | measrate = self._getMeasRate(integration, rate)
79 | self.i2c.writeto_mem(ALS_I2CADDR, ALS_MEAS_RATE_REG, bytearray([measrate]))
80 |
81 | time.sleep(0.01)
82 |
83 | def _getContr(self, gain):
84 | return ((gain & 0x07) << 2) + 0x01
85 |
86 | def _getMeasRate(self, integration, rate):
87 | return ((integration & 0x07) << 3) + (rate & 0x07)
88 |
89 | def _getWord(self, high, low):
90 | return ((high & 0xFF) << 8) + (low & 0xFF)
91 |
92 | def light(self):
93 | ch1low = self.i2c.readfrom_mem(ALS_I2CADDR , ALS_DATA_CH1_LOW, 1)
94 | ch1high = self.i2c.readfrom_mem(ALS_I2CADDR , ALS_DATA_CH1_HIGH, 1)
95 | data1 = int(self._getWord(ch1high[0], ch1low[0]))
96 |
97 | ch0low = self.i2c.readfrom_mem(ALS_I2CADDR , ALS_DATA_CH0_LOW, 1)
98 | ch0high = self.i2c.readfrom_mem(ALS_I2CADDR , ALS_DATA_CH0_HIGH, 1)
99 | data0 = int(self._getWord(ch0high[0], ch0low[0]))
100 |
101 | return (data0, data1)
102 |
103 | def lux(self):
104 | # Calculate Lux value from formular in Appendix A of the datasheet
105 | light_level = self.light()
106 | if light_level[0]+light_level[1] > 0:
107 | ratio = light_level[1]/(light_level[0]+light_level[1])
108 | if ratio < 0.45:
109 | return (1.7743 * light_level[0] + 1.1059 * light_level[1]) / self.ALS_GAIN_VALUES[self.gain] / self.ALS_INT_VALUES[self.integration]
110 | elif ratio < 0.64 and ratio >= 0.45:
111 | return (4.2785 * light_level[0] - 1.9548 * light_level[1]) / self.ALS_GAIN_VALUES[self.gain] / self.ALS_INT_VALUES[self.integration]
112 | elif ratio < 0.85 and ratio >= 0.64:
113 | return (0.5926 * light_level[0] + 0.1185 * light_level[1]) / self.ALS_GAIN_VALUES[self.gain] / self.ALS_INT_VALUES[self.integration]
114 | else:
115 | return 0
116 | else:
117 | return 0
118 |
--------------------------------------------------------------------------------
/shields/lib/MFRC630.mpy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/shields/lib/MFRC630.mpy
--------------------------------------------------------------------------------
/shields/lib/MFRC630.mpy-1.18:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pycom/pycom-libraries/75d0e67cb421e0576a3a9677bb0d9d81f27ebdb7/shields/lib/MFRC630.mpy-1.18
--------------------------------------------------------------------------------
/shields/lib/MPL3115A2.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import time
12 | from machine import I2C
13 |
14 | ALTITUDE = const(0)
15 | PRESSURE = const(1)
16 |
17 | class MPL3115A2exception(Exception):
18 | pass
19 |
20 | class MPL3115A2:
21 | MPL3115_I2CADDR = const(0x60)
22 | MPL3115_STATUS = const(0x00)
23 | MPL3115_PRESSURE_DATA_MSB = const(0x01)
24 | MPL3115_PRESSURE_DATA_CSB = const(0x02)
25 | MPL3115_PRESSURE_DATA_LSB = const(0x03)
26 | MPL3115_TEMP_DATA_MSB = const(0x04)
27 | MPL3115_TEMP_DATA_LSB = const(0x05)
28 | MPL3115_DR_STATUS = const(0x06)
29 | MPL3115_DELTA_DATA = const(0x07)
30 | MPL3115_WHO_AM_I = const(0x0c)
31 | MPL3115_FIFO_STATUS = const(0x0d)
32 | MPL3115_FIFO_DATA = const(0x0e)
33 | MPL3115_FIFO_SETUP = const(0x0e)
34 | MPL3115_TIME_DELAY = const(0x10)
35 | MPL3115_SYS_MODE = const(0x11)
36 | MPL3115_INT_SORCE = const(0x12)
37 | MPL3115_PT_DATA_CFG = const(0x13)
38 | MPL3115_BAR_IN_MSB = const(0x14)
39 | MPL3115_P_ARLARM_MSB = const(0x16)
40 | MPL3115_T_ARLARM = const(0x18)
41 | MPL3115_P_ARLARM_WND_MSB = const(0x19)
42 | MPL3115_T_ARLARM_WND = const(0x1b)
43 | MPL3115_P_MIN_DATA = const(0x1c)
44 | MPL3115_T_MIN_DATA = const(0x1f)
45 | MPL3115_P_MAX_DATA = const(0x21)
46 | MPL3115_T_MAX_DATA = const(0x24)
47 | MPL3115_CTRL_REG1 = const(0x26)
48 | MPL3115_CTRL_REG2 = const(0x27)
49 | MPL3115_CTRL_REG3 = const(0x28)
50 | MPL3115_CTRL_REG4 = const(0x29)
51 | MPL3115_CTRL_REG5 = const(0x2a)
52 | MPL3115_OFFSET_P = const(0x2b)
53 | MPL3115_OFFSET_T = const(0x2c)
54 | MPL3115_OFFSET_H = const(0x2d)
55 |
56 | def __init__(self, pysense = None, sda = 'P22', scl = 'P21', mode = PRESSURE):
57 | if pysense is not None:
58 | self.i2c = pysense.i2c
59 | else:
60 | self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
61 |
62 | self.STA_reg = bytearray(1)
63 | self.mode = mode
64 |
65 | if self.mode is PRESSURE:
66 | self.i2c.writeto_mem(MPL3115_I2CADDR, MPL3115_CTRL_REG1, bytes([0x38])) # barometer mode, not raw, oversampling 128, minimum time 512 ms
67 | self.i2c.writeto_mem(MPL3115_I2CADDR, MPL3115_PT_DATA_CFG, bytes([0x07])) # no events detected
68 | self.i2c.writeto_mem(MPL3115_I2CADDR, MPL3115_CTRL_REG1, bytes([0x39])) # active
69 | elif self.mode is ALTITUDE:
70 | self.i2c.writeto_mem(MPL3115_I2CADDR, MPL3115_CTRL_REG1, bytes([0xB8])) # altitude mode, not raw, oversampling 128, minimum time 512 ms
71 | self.i2c.writeto_mem(MPL3115_I2CADDR, MPL3115_PT_DATA_CFG, bytes([0x07])) # no events detected
72 | self.i2c.writeto_mem(MPL3115_I2CADDR, MPL3115_CTRL_REG1, bytes([0xB9])) # active
73 | else:
74 | raise MPL3115A2exception("Invalid Mode MPL3115A2")
75 |
76 | if self._read_status():
77 | pass
78 | else:
79 | raise MPL3115A2exception("Error with MPL3115A2")
80 |
81 | def _read_status(self):
82 | read_attempts = 0
83 | while read_attempts < 500:
84 | self.i2c.readfrom_mem_into(MPL3115_I2CADDR, MPL3115_STATUS, self.STA_reg)
85 | read_attempts += 1
86 |
87 | if(self.STA_reg[0] == 0):
88 | time.sleep(0.01)
89 | pass
90 | elif(self.STA_reg[0] & 0x04) == 4:
91 | return True
92 | else:
93 | return False
94 |
95 | # If we get here the sensor isn't responding. Reset it so next time in it should work
96 | self.i2c.writeto_mem(MPL3115_I2CADDR, MPL3115_CTRL_REG1, bytes([0x00])) # put into standby
97 | self.i2c.writeto_mem(MPL3115_I2CADDR, MPL3115_CTRL_REG1, bytes([0x04])) # reset
98 | return False
99 |
100 | def pressure(self):
101 | if self.mode == ALTITUDE:
102 | raise MPL3115A2exception("Incorrect Measurement Mode MPL3115A2")
103 |
104 | OUT_P_MSB = self.i2c.readfrom_mem(MPL3115_I2CADDR, MPL3115_PRESSURE_DATA_MSB,1)
105 | OUT_P_CSB = self.i2c.readfrom_mem(MPL3115_I2CADDR, MPL3115_PRESSURE_DATA_CSB,1)
106 | OUT_P_LSB = self.i2c.readfrom_mem(MPL3115_I2CADDR, MPL3115_PRESSURE_DATA_LSB,1)
107 |
108 | return float((OUT_P_MSB[0] << 10) + (OUT_P_CSB[0] << 2) + ((OUT_P_LSB[0] >> 6) & 0x03) + ((OUT_P_LSB[0] >> 4) & 0x03) / 4.0)
109 |
110 | def altitude(self):
111 | if self.mode == PRESSURE:
112 | raise MPL3115A2exception("Incorrect Measurement Mode MPL3115A2")
113 |
114 | OUT_P_MSB = self.i2c.readfrom_mem(MPL3115_I2CADDR, MPL3115_PRESSURE_DATA_MSB,1)
115 | OUT_P_CSB = self.i2c.readfrom_mem(MPL3115_I2CADDR, MPL3115_PRESSURE_DATA_CSB,1)
116 | OUT_P_LSB = self.i2c.readfrom_mem(MPL3115_I2CADDR, MPL3115_PRESSURE_DATA_LSB,1)
117 |
118 | alt_int = (OUT_P_MSB[0] << 8) + (OUT_P_CSB[0])
119 | alt_frac = ((OUT_P_LSB[0] >> 4) & 0x0F)
120 |
121 | if alt_int > 32767:
122 | alt_int -= 65536
123 |
124 | return float(alt_int + alt_frac / 16.0)
125 |
126 | def temperature(self):
127 | OUT_T_MSB = self.i2c.readfrom_mem(MPL3115_I2CADDR, MPL3115_TEMP_DATA_MSB,1)
128 | OUT_T_LSB = self.i2c.readfrom_mem(MPL3115_I2CADDR, MPL3115_TEMP_DATA_LSB,1)
129 |
130 | temp_int = OUT_T_MSB[0]
131 | temp_frac = OUT_T_LSB[0]
132 |
133 | if temp_int > 127:
134 | temp_int -= 256
135 |
136 | return float(temp_int + temp_frac / 256.0)
137 |
--------------------------------------------------------------------------------
/shields/lib/SI7006A20.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2019, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import time
12 | from machine import I2C
13 | import math
14 |
15 | __version__ = '0.0.2'
16 |
17 | class SI7006A20:
18 | """ class for handling the temperature sensor SI7006-A20
19 | +/- 1 deg C error for temperature
20 | +/- 5% error for relative humidity
21 | datasheet available at https://www.silabs.com/documents/public/data-sheets/Si7006-A20.pdf """
22 |
23 | SI7006A20_I2C_ADDR = const(0x40)
24 |
25 | # I2C commands
26 | TEMP_NOHOLDMASTER = const(0xF3)
27 | HUMD_NOHOLDMASTER = const(0xF5)
28 | WRITE_USER_REG1 = const(0xE6)
29 | READ_USER_REG1 = const(0xE7)
30 | WRITE_HEATER_CTRL_REG = const(0x51)
31 | READ_HEATER_CTRL_REG = const(0x11)
32 |
33 | # Register masks and offsets
34 | USER_REG1_HTR_ENABLE_MASK = const(0b00000100)
35 | USER_REG1_HTR_ENABLE_OFFSET = const(0x02)
36 | HTR_CTRL_REG_MASK = const(0b00001111)
37 |
38 | def __init__(self, pysense = None, sda = 'P22', scl = 'P21'):
39 | if pysense is not None:
40 | self.i2c = pysense.i2c
41 | else:
42 | self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
43 |
44 | def _getWord(self, high, low):
45 | return ((high & 0xFF) << 8) + (low & 0xFF)
46 |
47 | def temperature(self):
48 | """ obtaining the temperature(degrees Celsius) measured by sensor """
49 | self.i2c.writeto(SI7006A20_I2C_ADDR, bytearray([0xF3]))
50 | time.sleep(0.5)
51 | data = self.i2c.readfrom(SI7006A20_I2C_ADDR, 3)
52 | #print("CRC Raw temp data: " + hex(data[0]*65536 + data[1]*256 + data[2]))
53 | data = self._getWord(data[0], data[1])
54 | temp = ((175.72 * data) / 65536.0) - 46.85
55 | return temp
56 |
57 | def humidity(self):
58 | """ obtaining the relative humidity(%) measured by sensor """
59 | self.i2c.writeto(SI7006A20_I2C_ADDR, bytearray([0xF5]))
60 | time.sleep(0.5)
61 | data = self.i2c.readfrom(SI7006A20_I2C_ADDR, 2)
62 | data = self._getWord(data[0], data[1])
63 | humidity = ((125.0 * data) / 65536.0) - 6.0
64 | return humidity
65 |
66 | def read_user_reg(self):
67 | """ reading the user configuration register """
68 | self.i2c.writeto(SI7006A20_I2C_ADDR, bytearray([READ_USER_REG1]))
69 | time.sleep(0.5)
70 | data = self.i2c.readfrom(SI7006A20_I2C_ADDR, 1)
71 | return data[0]
72 |
73 | def read_heater_reg(self):
74 | """ reading the heater configuration register """
75 | self.i2c.writeto(SI7006A20_I2C_ADDR, bytearray([READ_HEATER_CTRL_REG]))
76 | time.sleep(0.5)
77 | data = self.i2c.readfrom(SI7006A20_I2C_ADDR, 1)
78 | return data[0]
79 |
80 | def write_heater_reg(self, heater_value):
81 | """ writing the heater configuration register """
82 | # We should only set the bottom four bits of this register
83 | heater_setting = heater_value & HTR_CTRL_REG_MASK
84 | self.write_reg(WRITE_HEATER_CTRL_REG, heater_setting)
85 |
86 | def heater_control(self, on_off):
87 | """ turn the heater on or off """
88 | # Get current settings for everything else
89 | user_reg = self.read_user_reg()
90 | # Set the heater bit
91 | user_reg = (user_reg & ~USER_REG1_HTR_ENABLE_MASK) | (on_off << USER_REG1_HTR_ENABLE_OFFSET)
92 | self.write_reg(WRITE_USER_REG1, user_reg)
93 |
94 | def read_electronic_id(self):
95 | """ reading electronic identifier """
96 | self.i2c.writeto(SI7006A20_I2C_ADDR, bytearray([0xFA]) + bytearray([0x0F]))
97 | time.sleep(0.5)
98 | sna = self.i2c.readfrom(SI7006A20_I2C_ADDR, 4)
99 | time.sleep(0.1)
100 | self.i2c.writeto(SI7006A20_I2C_ADDR, bytearray([0xFC]) + bytearray([0xC9]))
101 | time.sleep(0.5)
102 | snb = self.i2c.readfrom(SI7006A20_I2C_ADDR, 4)
103 | return [sna[0], sna[1], sna[2], sna[3], snb[0], snb[1], snb[2], snb[3]]
104 |
105 | def read_firmware(self):
106 | """ reading firmware version """
107 | self.i2c.writeto(SI7006A20_I2C_ADDR, bytearray([0x84])+ bytearray([0xB8]))
108 | time.sleep(0.5)
109 | fw = self.i2c.readfrom(SI7006A20_I2C_ADDR, 1)
110 | return fw[0]
111 |
112 | def read_reg(self, reg_addr):
113 | """ reading a register """
114 | self.i2c.writeto(SI7006A20_I2C_ADDR, bytearray([reg_addr]))
115 | time.sleep(0.5)
116 | data = self.i2c.readfrom(SI7006A20_I2C_ADDR, 1)
117 | return data[0]
118 |
119 | def write_reg(self, reg_addr, value):
120 | """ writing a register """
121 | self.i2c.writeto(SI7006A20_I2C_ADDR, bytearray([reg_addr])+bytearray([value]))
122 | time.sleep(0.1)
123 |
124 | def dew_point(self):
125 | """ computing the dew pointe temperature (deg C) for the current Temperature and Humidity measured pair
126 | at dew-point temperature the relative humidity is 100% """
127 | temp = self.temperature()
128 | humid = self.humidity()
129 | h = (math.log(humid, 10) - 2) / 0.4343 + (17.62 * temp) / (243.12 + temp)
130 | dew_p = 243.12 * h / (17.62 - h)
131 | return dew_p
132 |
133 | def humid_ambient(self, t_ambient, dew_p = None):
134 | """ returns the relative humidity compensated for the current Ambient temperature
135 | for ex: T-Ambient is 24.4 degC, but sensor indicates Temperature = 31.65 degC and Humidity = 47.3%
136 | -> then the actual Relative Humidity is 72.2%
137 | this is computed because the dew-point should be the same """
138 | if dew_p is None:
139 | dew_p = self.dew_point()
140 | h = 17.62 * dew_p / (243.12 + dew_p)
141 | h_ambient = math.pow(10, (h - (17.62 * t_ambient) / (243.12 + t_ambient)) * 0.4343 + 2)
142 | return h_ambient
143 |
--------------------------------------------------------------------------------
/shields/pyscan_1.py:
--------------------------------------------------------------------------------
1 | '''
2 | Simple Pyscan NFC / MiFare Classic Example
3 | Copyright (c) 2019, Pycom Limited.
4 |
5 | This example continuously sends a REQA for ISO14443A card type
6 | If a card is discovered, it will read the UID
7 | If DECODE_CARD = True, will attempt to authenticate with CARDkey
8 | If authentication succeeds will attempt to read sectors from the card
9 | '''
10 |
11 | from pycoproc_1 import Pycoproc
12 | from MFRC630 import MFRC630
13 | from LIS2HH12 import LIS2HH12
14 | from LTR329ALS01 import LTR329ALS01
15 | import time
16 | import pycom
17 |
18 | #add your card UID here
19 | VALID_CARDS = [[0x43, 0x95, 0xDD, 0xF8],
20 | [0x43, 0x95, 0xDD, 0xF9],
21 | [0x46, 0x5A, 0xEB, 0x7D, 0x8A, 0x08, 0x04]]
22 |
23 |
24 | # This is the default key for an unencrypted MiFare card
25 | CARDkey = [ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ]
26 | DECODE_CARD = False
27 |
28 | py = Pycoproc(Pycoproc.PYSCAN)
29 | nfc = MFRC630(py)
30 | lt = LTR329ALS01(py)
31 | li = LIS2HH12(py)
32 |
33 | pybytes_enabled = False
34 | if 'pybytes' in globals():
35 | if(pybytes.isconnected()):
36 | print('Pybytes is connected, sending signals to Pybytes')
37 | pybytes_enabled = True
38 |
39 | RGB_BRIGHTNESS = 0x8
40 |
41 | RGB_RED = (RGB_BRIGHTNESS << 16)
42 | RGB_GREEN = (RGB_BRIGHTNESS << 8)
43 | RGB_BLUE = (RGB_BRIGHTNESS)
44 |
45 | counter = 0
46 |
47 | def check_uid(uid, len):
48 | return VALID_CARDS.count(uid[:len])
49 |
50 | def send_sensor_data(name, timeout):
51 | if(pybytes_enabled):
52 | while(True):
53 | pybytes.send_signal(2, lt.light())
54 | pybytes.send_signal(3, li.acceleration())
55 | time.sleep(timeout)
56 |
57 | # Make sure heartbeat is disabled before setting RGB LED
58 | pycom.heartbeat(False)
59 |
60 | # Initialise the MFRC630 with some settings
61 | nfc.mfrc630_cmd_init()
62 |
63 | print('Scanning for cards')
64 | while True:
65 | # Send REQA for ISO14443A card type
66 | atqa = nfc.mfrc630_iso14443a_WUPA_REQA(nfc.MFRC630_ISO14443_CMD_REQA)
67 | if (atqa != 0):
68 | # A card has been detected, read UID
69 | print('A card has been detected, reading its UID ...')
70 | uid = bytearray(10)
71 | uid_len = nfc.mfrc630_iso14443a_select(uid)
72 | print('UID has length {}'.format(uid_len))
73 | if (uid_len > 0):
74 | # A valid UID has been detected, print details
75 | counter += 1
76 | print("%d\tUID [%d]: %s" % (counter, uid_len, nfc.format_block(uid, uid_len)))
77 | if DECODE_CARD:
78 | # Try to authenticate with CARD key
79 | nfc.mfrc630_cmd_load_key(CARDkey)
80 | for sector in range(0, 16):
81 | if (nfc.mfrc630_MF_auth(uid, nfc.MFRC630_MF_AUTH_KEY_A, sector * 4)):
82 | pycom.rgbled(RGB_GREEN)
83 | # Authentication was sucessful, read card data
84 | readbuf = bytearray(16)
85 | for b in range(0, 4):
86 | f_sect = sector * 4 + b
87 | len = nfc.mfrc630_MF_read_block(f_sect, readbuf)
88 | print("\t\tSector %s: Block: %s: %s" % (nfc.format_block([sector], 1), nfc.format_block([b], 1), nfc.format_block(readbuf, len)))
89 | else:
90 | print("Authentication denied for sector %s!" % nfc.format_block([sector], 1))
91 | pycom.rgbled(RGB_RED)
92 | # It is necessary to call mfrc630_MF_deauth after authentication
93 | # Although this is also handled by the reset / init cycle
94 | nfc.mfrc630_MF_deauth()
95 | else:
96 | #check if card uid is listed in VALID_CARDS
97 | if (check_uid(list(uid), uid_len)) > 0:
98 | print('Card is listed, turn LED green')
99 | pycom.rgbled(RGB_GREEN)
100 | if(pybytes_enabled):
101 | pybytes.send_signal(1, ('Card is listed', uid))
102 | else:
103 | print('Card is not listed, turn LED red')
104 | pycom.rgbled(RGB_RED)
105 | if(pybytes_enabled):
106 | pybytes.send_signal(1, ('Unauthorized card detected', uid))
107 |
108 | else:
109 | pycom.rgbled(RGB_BLUE)
110 | # We could go into power saving mode here... to be investigated
111 | nfc.mfrc630_cmd_reset()
112 | time.sleep(.5)
113 | # Re-Initialise the MFRC630 with settings as these got wiped during reset
114 | nfc.mfrc630_cmd_init()
115 |
--------------------------------------------------------------------------------
/shields/pysense_1.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | # See https://docs.pycom.io for more information regarding library specifics
12 |
13 | import time
14 | import pycom
15 | from pycoproc_1 import Pycoproc
16 | import machine
17 |
18 | from LIS2HH12 import LIS2HH12
19 | from SI7006A20 import SI7006A20
20 | from LTR329ALS01 import LTR329ALS01
21 | from MPL3115A2 import MPL3115A2,ALTITUDE,PRESSURE
22 |
23 | pycom.heartbeat(False)
24 | pycom.rgbled(0x0A0A08) # white
25 |
26 | py = Pycoproc(Pycoproc.PYSENSE)
27 |
28 | pybytes_enabled = False
29 | if 'pybytes' in globals():
30 | if(pybytes.isconnected()):
31 | print('Pybytes is connected, sending signals to Pybytes')
32 | pybytes_enabled = True
33 |
34 | mp = MPL3115A2(py,mode=ALTITUDE) # Returns height in meters. Mode may also be set to PRESSURE, returning a value in Pascals
35 | print("MPL3115A2 temperature: " + str(mp.temperature()))
36 | print("Altitude: " + str(mp.altitude()))
37 | mpp = MPL3115A2(py,mode=PRESSURE) # Returns pressure in Pa. Mode may also be set to ALTITUDE, returning a value in meters
38 | print("Pressure: " + str(mpp.pressure()))
39 |
40 | si = SI7006A20(py)
41 | print("Temperature: " + str(si.temperature())+ " deg C and Relative Humidity: " + str(si.humidity()) + " %RH")
42 | print("Dew point: "+ str(si.dew_point()) + " deg C")
43 | t_ambient = 24.4
44 | print("Humidity Ambient for " + str(t_ambient) + " deg C is " + str(si.humid_ambient(t_ambient)) + "%RH")
45 |
46 |
47 | lt = LTR329ALS01(py)
48 | print("Light (channel Blue lux, channel Red lux): " + str(lt.light()))
49 |
50 | li = LIS2HH12(py)
51 | print("Acceleration: " + str(li.acceleration()))
52 | print("Roll: " + str(li.roll()))
53 | print("Pitch: " + str(li.pitch()))
54 |
55 | # set your battery voltage limits here
56 | vmax = 4.2
57 | vmin = 3.3
58 | battery_voltage = py.read_battery_voltage()
59 | battery_percentage = (battery_voltage - vmin / (vmax - vmin))*100
60 | print("Battery voltage: " + str(py.read_battery_voltage()), " percentage: ", battery_percentage)
61 | if(pybytes_enabled):
62 | pybytes.send_signal(1, mpp.pressure())
63 | pybytes.send_signal(2, si.temperature())
64 | pybytes.send_signal(3, lt.light())
65 | pybytes.send_signal(4, li.acceleration())
66 | pybytes.send_battery_level(int(battery_percentage))
67 | print("Sent data to pybytes")
68 |
69 | time.sleep(5)
70 | py.setup_sleep(10)
71 | py.go_to_sleep()
72 |
--------------------------------------------------------------------------------
/shields/pysense_2.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | # See https://docs.pycom.io for more information regarding library specifics
12 |
13 | import time
14 | import pycom
15 | from pycoproc_2 import Pycoproc
16 | import machine
17 |
18 | from LIS2HH12 import LIS2HH12
19 | from SI7006A20 import SI7006A20
20 | from LTR329ALS01 import LTR329ALS01
21 | from MPL3115A2 import MPL3115A2,ALTITUDE,PRESSURE
22 |
23 | pycom.heartbeat(False)
24 | pycom.rgbled(0x0A0A08) # white
25 |
26 | py = Pycoproc()
27 | if py.read_product_id() != Pycoproc.USB_PID_PYSENSE:
28 | raise Exception('Not a Pysense')
29 |
30 | pybytes_enabled = False
31 | if 'pybytes' in globals():
32 | if(pybytes.isconnected()):
33 | print('Pybytes is connected, sending signals to Pybytes')
34 | pybytes_enabled = True
35 |
36 | mp = MPL3115A2(py,mode=ALTITUDE) # Returns height in meters. Mode may also be set to PRESSURE, returning a value in Pascals
37 | print("MPL3115A2 temperature: " + str(mp.temperature()))
38 | print("Altitude: " + str(mp.altitude()))
39 | mpp = MPL3115A2(py,mode=PRESSURE) # Returns pressure in Pa. Mode may also be set to ALTITUDE, returning a value in meters
40 | print("Pressure: " + str(mpp.pressure()))
41 |
42 |
43 | si = SI7006A20(py)
44 | print("Temperature: " + str(si.temperature())+ " deg C and Relative Humidity: " + str(si.humidity()) + " %RH")
45 | print("Dew point: "+ str(si.dew_point()) + " deg C")
46 | t_ambient = 24.4
47 | print("Humidity Ambient for " + str(t_ambient) + " deg C is " + str(si.humid_ambient(t_ambient)) + "%RH")
48 |
49 |
50 | lt = LTR329ALS01(py)
51 | print("Light (channel Blue, channel Red): " + str(lt.light())," Lux: ", str(lt.lux()), "lx")
52 |
53 | li = LIS2HH12(py)
54 | print("Acceleration: " + str(li.acceleration()))
55 | print("Roll: " + str(li.roll()))
56 | print("Pitch: " + str(li.pitch()))
57 |
58 | print("Battery voltage: " + str(py.read_battery_voltage()))
59 |
60 | # set your battery voltage limits here
61 | vmax = 4.2
62 | vmin = 3.3
63 | battery_voltage = py.read_battery_voltage()
64 | battery_percentage = (battery_voltage - vmin / (vmax - vmin))*100
65 | print("Battery voltage: " + str(py.read_battery_voltage()), " percentage: ", battery_percentage)
66 | if(pybytes_enabled):
67 | pybytes.send_signal(1, mpp.pressure())
68 | pybytes.send_signal(2, si.temperature())
69 | pybytes.send_signal(3, lt.light())
70 | pybytes.send_signal(4, li.acceleration())
71 | pybytes.send_battery_level(int(battery_percentage))
72 | print("Sent data to pybytes")
73 |
--------------------------------------------------------------------------------
/shields/pytrack_1.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import machine
12 | import math
13 | import network
14 | import os
15 | import time
16 | import utime
17 | import gc
18 | from machine import RTC
19 | from machine import SD
20 | from L76GNSS import L76GNSS
21 | from pycoproc_1 import Pycoproc
22 |
23 | time.sleep(2)
24 | gc.enable()
25 |
26 | # setup rtc
27 | rtc = machine.RTC()
28 | rtc.ntp_sync("pool.ntp.org")
29 | utime.sleep_ms(750)
30 | print('\nRTC Set from NTP to UTC:', rtc.now())
31 | utime.timezone(7200)
32 | print('Adjusted from UTC to EST timezone', utime.localtime(), '\n')
33 |
34 | py = Pycoproc(Pycoproc.PYTRACK)
35 | l76 = L76GNSS(py, timeout=30)
36 |
37 | pybytes_enabled = False
38 | if 'pybytes' in globals():
39 | if(pybytes.isconnected()):
40 | print('Pybytes is connected, sending signals to Pybytes')
41 | pybytes_enabled = True
42 |
43 | # sd = SD()
44 | # os.mount(sd, '/sd')
45 | # f = open('/sd/gps-record.txt', 'w')
46 |
47 | while (True):
48 | coord = l76.coordinates()
49 | #f.write("{} - {}\n".format(coord, rtc.now()))
50 | print("{} - {} - {}".format(coord, rtc.now(), gc.mem_free()))
51 | if(pybytes_enabled):
52 | pybytes.send_signal(1, coord)
53 | time.sleep(10)
54 |
55 | """
56 | # sleep procedure
57 | time.sleep(3)
58 | py.setup_sleep(10)
59 | py.go_to_sleep()
60 | """
61 |
--------------------------------------------------------------------------------
/shields/pytrack_2.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | import machine
12 | import math
13 | import network
14 | import os
15 | import time
16 | import utime
17 | import gc
18 | import pycom
19 | from machine import RTC
20 | from machine import SD
21 | from L76GNSS import L76GNSS
22 | from pycoproc_2 import Pycoproc
23 |
24 | pycom.heartbeat(False)
25 | pycom.rgbled(0x0A0A08) # white
26 |
27 | time.sleep(2)
28 | gc.enable()
29 |
30 | # setup rtc
31 | rtc = machine.RTC()
32 | rtc.ntp_sync("pool.ntp.org")
33 | utime.sleep_ms(750)
34 | print('\nRTC Set from NTP to UTC:', rtc.now())
35 | utime.timezone(7200)
36 | print('Adjusted from UTC to EST timezone', utime.localtime(), '\n')
37 |
38 | py = Pycoproc()
39 | if py.read_product_id() != Pycoproc.USB_PID_PYTRACK:
40 | raise Exception('Not a Pytrack')
41 |
42 | time.sleep(1)
43 | l76 = L76GNSS(py, timeout=30, buffer=512)
44 |
45 | pybytes_enabled = False
46 | if 'pybytes' in globals():
47 | if(pybytes.isconnected()):
48 | print('Pybytes is connected, sending signals to Pybytes')
49 | pybytes_enabled = True
50 |
51 | # sd = SD()
52 | # os.mount(sd, '/sd')
53 | # f = open('/sd/gps-record.txt', 'w')
54 |
55 | while (True):
56 | coord = l76.coordinates()
57 | #f.write("{} - {}\n".format(coord, rtc.now()))
58 | print("{} - {} - {}".format(coord, rtc.now(), gc.mem_free()))
59 | if(pybytes_enabled):
60 | pybytes.send_signal(1, coord)
61 | time.sleep(10)
62 |
63 | """
64 | # sleep procedure
65 | time.sleep(3)
66 | py.setup_sleep(10)
67 | py.go_to_sleep()
68 | """
69 |
--------------------------------------------------------------------------------
/shields/shield_2.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # Copyright (c) 2020, Pycom Limited.
4 | #
5 | # This software is licensed under the GNU GPL version 3 or any
6 | # later version, with permitted additional terms. For more information
7 | # see the Pycom Licence v1.0 document supplied with this file, or
8 | # available at https://www.pycom.io/opensource/licensing
9 | #
10 |
11 | # This script support Pysense 2 and Pytrack 2
12 | # It demonstrates two examples:
13 | # * go to ultra low power mode (~10uA @3.75V) with all sensors, incl accelerometer and also pycom module (Fipy, Gpy, etc) off - tap the MCLR button for this
14 | # * go to low power mode (~165uA @3.75V) with accelerometer on, pycom module in deepsleep and wake from accelerometer interrupt - hold the MCLR button down for this
15 |
16 | # See https://docs.pycom.io for more information regarding library specifics
17 |
18 | import time
19 | import pycom
20 | import struct
21 | from machine import Pin
22 | from pycoproc_2 import Pycoproc
23 | import machine
24 | from LIS2HH12 import LIS2HH12
25 |
26 | def accelerometer():
27 | print("ACCELEROMETER:", "accel:", accelerometer_sensor.acceleration(), "roll:", accelerometer_sensor.roll(), "pitch:", accelerometer_sensor.pitch(), "x/y/z:", accelerometer_sensor.x, accelerometer_sensor.y, accelerometer_sensor.z )
28 |
29 | def activity_int_handler(pin_o):
30 | if pin_o():
31 | print('[Activity]')
32 | pycom.rgbled(0x00000A) # blue
33 | else:
34 | print('[Inactivity]')
35 | pycom.rgbled(0x0A0A00) # yellow
36 |
37 | def activity_int_handler_none(pin_o):
38 | pass
39 |
40 | def blink(color=0x0a0a0a, ct=5, on_ms=100, off_ms=100 ):
41 | while ct >= 0 :
42 | ct -= 1
43 | pycom.rgbled(color)
44 | time.sleep_ms(on_ms)
45 | pycom.rgbled(0x000000)
46 | time.sleep_ms(off_ms)
47 |
48 | def wait(color=0x0a0a0a, hold_timeout_ms=3000):
49 | print(" - tap MCLR button to go to ultra low power mode (everything off)")
50 | print(" - hold MCLR button down for", round(hold_timeout_ms/1000,1), "sec to go to low power mode and wake from accelerometer")
51 | print("wait for button ...")
52 | ct = 0
53 | pressed_time_ms = 0
54 | dot = '.'
55 | while True:
56 | if pycoproc.button_pressed():
57 | if pressed_time_ms == 0:
58 | # the button just started to be pressed
59 | pressed_time_ms = time.ticks_ms()
60 | print("button pressed")
61 | pycom.rgbled(color)
62 | dot = '*'
63 | else:
64 | # the button is still being held down
65 | if time.ticks_ms() - pressed_time_ms > hold_timeout_ms:
66 | pycom.rgbled(0)
67 | dot = '_'
68 | else:
69 | if pressed_time_ms != 0:
70 | # the button was released
71 | print("button released")
72 | if time.ticks_ms() - pressed_time_ms > hold_timeout_ms:
73 | return True
74 | else:
75 | return False
76 | time.sleep(0.1)
77 | ct += 1
78 | if ct % 10 == 0:
79 | print(dot, end='')
80 |
81 | def pretty_reset_cause():
82 | mrc = machine.reset_cause()
83 | print('reset_cause', mrc, end=' ')
84 | if mrc == machine.PWRON_RESET:
85 | print("PWRON_RESET")
86 | # plug in
87 | # press reset button on module
88 | # reset button on JTAG board
89 | # core dump
90 | elif mrc == machine.HARD_RESET:
91 | print("HARD_RESET")
92 | elif mrc == machine.WDT_RESET:
93 | print("WDT_RESET")
94 | # machine.reset()
95 | elif mrc == machine.DEEPSLEEP_RESET:
96 | print("DEEPSLEEP_RESET")
97 | # machine.deepsleep()
98 | elif mrc == machine.SOFT_RESET:
99 | print("SOFT_RESET")
100 | # Ctrl-D
101 | elif mrc == machine.BROWN_OUT_RESET:
102 | print("BROWN_OUT_RESET")
103 |
104 | def pretty_wake_reason():
105 | mwr = machine.wake_reason()
106 | print("wake_reason", mwr, end=' ')
107 | if mwr[0] == machine.PWRON_WAKE:
108 | print("PWRON_WAKE")
109 | # reset button
110 | elif mwr[0] == machine.PIN_WAKE:
111 | print("PIN_WAKE")
112 | elif mwr[0] == machine.RTC_WAKE:
113 | print("RTC_WAKE")
114 | # from deepsleep
115 | elif mwr[0] == machine.ULP_WAKE:
116 | print("ULP_WAKE")
117 |
118 |
119 | ###############################################################
120 | sleep_time_s = 300 # 5 min
121 | pycom.heartbeat(False)
122 | pycom.rgbled(0x0a0a0a) # white
123 | import binascii
124 | import machine
125 | print(os.uname().sysname.lower() + '-' + binascii.hexlify(machine.unique_id()).decode("utf-8")[-4:], "pysense2")
126 |
127 | pretty_wake_reason()
128 | pretty_reset_cause()
129 | print("pycoproc init")
130 | pycoproc = Pycoproc()
131 | print("battery {:.2f} V".format(pycoproc.read_battery_voltage()))
132 |
133 | # init accelerometer
134 | accelerometer_sensor = LIS2HH12()
135 | # read accelerometer sensor values
136 | accelerometer()
137 | print("enable accelerometer interrupt")
138 |
139 | # enable_activity_interrupt( [mG], [ms], callback)
140 | # accelerometer_sensor.enable_activity_interrupt(8000, 200, activity_int_handler) # low sensitivty
141 | # accelerometer_sensor.enable_activity_interrupt(2000, 200, activity_int_handler) # medium sensitivity
142 | accelerometer_sensor.enable_activity_interrupt( 100, 200, activity_int_handler) # high sensitivity
143 | # accelerometer_sensor.enable_activity_interrupt(63, 160, activity_int_handler) # ultra sensitivty
144 |
145 | if wait(0x0A000A): # purple
146 | print("button was held")
147 | blink(0x000a00) # green
148 | print("enable pycom module to wake up from accelerometer interrupt")
149 | wake_pins = [Pin('P13', mode=Pin.IN, pull=Pin.PULL_DOWN)]
150 | machine.pin_sleep_wakeup(wake_pins, machine.WAKEUP_ANY_HIGH, True)
151 |
152 | print("put pycoproc to sleep and pycom module to deepsleep for", round(sleep_time_s/60,1), "minutes")
153 | pycoproc.setup_sleep(sleep_time_s)
154 | pycoproc.go_to_sleep(pycom_module_off=False, accelerometer_off=False, wake_interrupt=True)
155 | machine.deepsleep(sleep_time_s * 1000)
156 | else:
157 | print("button was tapped")
158 | blink(0x100600) # orange
159 | print("put pycoproc to sleep and turn pycom module off for", round(sleep_time_s/60,1), "minutes")
160 | pycoproc.setup_sleep(sleep_time_s)
161 | pycoproc.go_to_sleep()
162 |
163 | print("we never reach here!")
164 |
--------------------------------------------------------------------------------