Architecture version 2. ======================= The project of a microcontroller program for an escape room has the following structure: * config.json * boot.py * main.py * mqtt.py * app.py **If you don't use JSON and EscapeRoomMakers server we recommend to use** **Architecture 1.** These files are necessary for making a device for an escape room. The ``config.json`` file contains the configuration of the device. ============= =========== Key Description ============= =========== topic The topic that MQTT client will subscribe mqtt_host The address of MQTT broker mqtt_user The login for MQTT broker mqtt_password The password for MQTT broker ssid The SSID of the wireless network psk The Wi-Fi access password ============= =========== For exapmle: .. code:: python { "topic": "TOPIC", "mqtt_host": "HOST", "mqtt_user": "USER", "mqtt_password": "PASS", "ssid": "SSID", "psk": "PSK" } The microcontroller executes ``boot.py`` when it starts. It connects the device to the network using "ssid" and "psk" from config.json. **Usually, you should not modify it.** The microcontroller executes ``main.py`` when ``boot.py`` terminates. It checks a network connection then it tries to connect to the MQTT broker using credentials ("mqtt_host", "mqtt_user", "mqtt_password") from ``config.json``. If the attempt fails the microcontroller sleeps for a minute, then restarts. Otherwise, it subscribes on device topic, creates an ``App`` instance, calls instance ``start()`` method for a time, and executes the infinite loop that periodically checks income messages and calls ``loop()`` method of ``App`` instance. **Usually, you should not modify it.** The ``mqtt.py`` file contains custom mqtt client class. **Usually, you should not modify it.** .. class:: MQTTClient(topic, client_id, server, port=0, user=None, password=None, keepalive=0, ssl=False, ssl_params=dict) MQTT client class. The arguments are: * ``topic`` is a MQTT topic that microcontroller will be subscribed. * ``client_id`` is some unique client_id. We recommend to use ``nic.config('mac')`` * ``server`` is a MQTT server address. ``main.py`` file passes ``mqtt_host`` here. * ``port`` is a MQTT server port. Default MQTT port used by EscapeRoomMakers server is ``1883``. * ``user`` is a MQTT username. ``main.py`` file passes ``mqtt_user`` here. * ``password`` is a MQTT password. ``main.py`` file passes ``mqtt_password`` here. * ``keepalive`` is a MQTT keepalive. * ``ssl`` is MQTT require SSL. * ``ssl_params`` SSL parameters. .. method:: MQTTClient.set_callback(callback) Set callback that handles parsed package. The arguments is: * ``callback`` function that handles parsed package. Returns ``None``. .. method:: MQTTClient.subscribe(topic, qos=0) Subscribe on topic. The arguments are: * ``topic`` is a MQTT topic to subscribe. * ``qos`` is a MQTT QoS. Returns ``None``. .. method:: MQTTClient.publish(topic, msg, retain=False, qos=0) Publish message to topic. The arguments are: * ``topic`` is a MQTT topic to publish message. * ``msg`` is message to publish. * ``retain`` is a MQTT message retain parameter. * ``qos`` is a MQTT QoS. Returns ``None``. .. method:: MQTTClient.publish_event(call, args=None) Publish event to EscapeRoomMakers server. The arguments are: * ``call`` is an event. * ``args`` is a dict with event arguments. Returns ``None``. The ``App.py`` file contains the main class of microcontroller escape room application. .. class:: App(client) :noindex: App is the main class of microcontroller escape room application. **You need to implement it's methods to make an application.** The arguments are: * ``client`` is a MQTT client wrapper. The ``__init__`` should make this arguments members. .. method:: App.on_message(package) :noindex: The MQTT messages handler. The ``main.py`` calls this method when any MQTT message is received. The arguments are: * ``package`` is a parsed JSON as dict. Returns ``None``. .. method:: App.start() :noindex: Make some things after connection to MQTT. Usually this method sends greating message. **You should not initialize peripheral devices here. Do it in** ``__init__`` **instead.** Returns ``None``. .. method:: App.loop() :noindex: Make main periodically logic. Returns ``None``. File template:: import gc import utime class App: def __init__(self, client, topic): self.client = client self.topic = topic def on_message(self, package): print(package) self.client.publish('micropython', 'hello') def start(self): pass def loop(self): time.sleep_ms(1000) print(gc.mem_free())