Metadata-Version: 2.1
Name: mqtttasky-groupme
Version: 0.1.4
Summary: GroupMe bot to schedule tasks, display and speak notifications, and publish them over MQTT.
Home-page: https://github.com/haasr/mqtttttttasky_groupme
Author: Ryan Haas
Author-email: haasrr@etsu.edu
License: MIT
Description: *****************
        mqtttasky_groupme
        *****************
        
        Turn your Raspberry Pi into a Task notification system.
        *******************************************************
        | |task-notification|
        
        .. |task-notification| image:: images/task-notification.png
        
        .. contents:: Contents
        
        
        What is MQTTTasky?
        ##################
        | I once created a desktop application called Tasky which would allow
        | me to create tasks in sticky-note-like windows. I could set
        | notifications for each task and have notifications sent to my phone.
        | The UI was nice and but that was about it; Tasky was clunky and buggy
        | and I couldn't conventiently schedule tasks from my smart phone.
        
        | MQTTTasky is much less terrible, despite its name. The basic idea is,
        | using GroupMe on my phone, I can schedule a task, then A GroupMe bot
        | I have configured will interact with me and schedule the tasks. When
        | a task notification occurs, the Raspberry Pi running MQTTTasky will
        | display a notification window about the task and read the task aloud
        | using a separate GitHub project called simple_google_tts. Additionally,
        | when LEDs are connected to the Raspberry Pi's BCM pins 18, 23, and 24,
        | they serve as status lights. Of course, it wouldn't be MQTTTasky
        | without some MQTT action now would it? MQTTTasky connects to a Mosquito
        | broker and when a task notification occurs, the notification is also
        | published to pub/tasks. Payloads are encrypted with Fernet and a
        | base-64 32-byte key can be used by any MQTT client to decrypt the
        | message payloads using a Fernet decryption.
        |
        
        System Design
        #############
        | |system-design|
        
        .. |system-design| image:: images/system-design.png
            :height: 300
            :width: 750
        
        | In case my artistic endeavors are lost on you, I will try to explain
        | my system design. We can think of it in terms of the HTTP(S) side of
        | the architecture, what happens locally on Pi (Pi side?), and the MQTT
        | side.
        |
        | Sitting on the Raspberry Pi, we have the mqtttasky_groupme
        | package running. This package includes the GroupMe bot which communicates
        | with users over HTTP. The the bot code processes requests in the group
        | to act on the scheduling component of mqtttasky_groupme which schedules
        | tasks. So on the 'Pi side', the bot and the scheduler will blink the LEDs
        | to indicate the status of messages and task notifications. The scheduler
        | will display graphical task notifications at the notification time of
        | each task and it will also cause the task information to be read aloud
        | through a connected speaker using a system call to simple_google_tts.
        |
        | Lastly, mqtttasky_groupme also includes an MQTT client. When it is time
        | for a notification to be sent, the scheduler also calls on the MQTT client
        | to publish the data to the topic, 'pub/tasks'. The client publishes
        | payloads which are encrypted using Fernet encryption for which the client
        | provides the symmetric key during initial configuration so that another
        | MQTT client (such as the one contained in this repo in
        | ./node_mqtttasky_pi_client) can use the key to create Fernet tokens and
        | decrypt the payloads.
        |
        | The Node.js client pictured in the above design is an example of another
        | client which subscribes to 'pub/tasks' on the same broker as MQTTasky is
        | publishing to. For instructions on setting up a broker for which to connect
        | your clients, see the section, 'Setting up a Mosquitto broker'.
        |
        | For me, this design is nifty because it is fully functional with just one
        | Pi but the MQTT architecture allows me to implement multiple displays and/or
        | speakers for task notifications such as on my monitor, my Raspberry
        | Pi touch display, or even a television.
        
        Equipment/Requirements
        ######################
        - A Raspberry Pi 3B/3B+ or 4B/4B+ running Raspberry Pi OS w/ desktop
        - A display connected to the Raspberry Pi
        - A speaker connected to the Raspberry Pi
        - A stable Internet connection on the Pi
        - Three LED lights (preferably a red, yellow, and green)
        - Four female to male jumper wires
        - One ~100-220 Ohm resistor
        - One breadboard
        
        
        Setup
        #####
        
        Connecting the LEDs
        -------------------
        | Please refer to the following diagram (I tried):
        | |gpio-diagram|
        |
        | 1) Connect one jumper wire to physical pin 1 (3.3V); connect the other
        |    end to the positive side of the breadboard to share its voltage.
        |
        | 2) Connect the resistor to the positive side of the breadboard after
        |    the jumper wire.
        |
        | 3) Connect the longer end (anode) of the first (red) LED to the positive
        |    side of the breadboard after the resistor.
        |
        | 4) Connect the next wire to physical pin 12 (BCM 18); connect the other
        |    end to the shorter end (cathode) of the first (red) LED.
        |
        | 5) Connect the longer end (anode) of the second (yellow) LED to the
        |    positive side of the breadboard after the first LED.
        |
        | 6) Connect the next wire to physical pin 16 (BCM 23); connect the other
        |    end to the shorter end (cathode) of the second (yellow) LED.
        |
        | 7) Connect the longer end (anode) of the third (green) LED to the
        |    positive side of the breadboard after the second LED.
        |
        | 8) Connect the next and final wire to physical pin 18 (BCM 24); connect
        |    the other end to the shorter end (cathode) of the third (green) LED.
        |
        
        .. |gpio-diagram| image:: images/gpio-diagram.png
        
        Setting up simple_google_tts
        ----------------------------
        | 1) As per the instructions from `this link <https://github.com/alexylem/jarvis/issues/129#issuecomment-248072872>`_, download each of the following
        | files on your Raspberry Pi:
        |   - `libttspico-data <http://ftp.fr.debian.org/debian/pool/non-free/s/svox/libttspico-data_1.0+git20130326-3_all.deb>`_
        |   - `libttspico0_1.0 <http://ftp.fr.debian.org/debian/pool/non-free/s/svox/libttspico0_1.0+git20130326-3_armhf.deb>`_
        |   - `libttspico-utils <http://ftp.fr.debian.org/debian/pool/non-free/s/svox/libttspico-utils_1.0+git20130326-3_armhf.deb>`_
        |
        | 2) And following the same instructions, install each of the packages onto your Pi:
        
        .. code:: bash
        
            sudo dpkg -i libttspico-data_1.0+git20130326-3_all.deb
            sudo dpkg -i libttspico0_1.0+git20130326-3_armhf.deb
            sudo dpkg -i libttspico-utils_1.0+git20130326-3_armhf.deb
        
        | 3) If git is not installed, you will need to install it:
        
        .. code:: bash
        
            sudo apt install git
        
        | 4) As instrcuted in the `simple_google_tts readme <https://github.com/glutanimate/simple-google-tts>`_, run the following command:
        |
        
        .. code:: bash
        
            sudo apt-get install xsel libnotify-bin libttspico0 libttspico-utils libttspico-data libwww-perl libwww-mechanize-perl libhtml-tree-perl sox libsox-fmt-mp3
        
        | 5) Clone the repo into the home directory and then open ~/.bashrc:
        
        .. code:: bash
        
            cd /home/pi; git clone https://github.com/Glutanimate/simple-google-tts.git
            nano .bashrc
        
        | 6) On a new line, at the end of .bashrc, add the following:
        
        .. code:: bash
        
            export PATH="$PATH:`pwd`/simple-google-tts"
        
        |
        
        Installing the Python packages
        ------------------------------
        | 1) First, ensure python3-pip is installed on your Raspberry Pi:
        
        .. code:: bash
        
            sudo apt install python3-pip
        
        | 2) Now install mqtttasky_groupme from the package index:
        
        .. code:: bash
        
            pip3 install mqtttasky-groupme==0.1.4
        
        |
        
        Registering for GroupMe, Creating a Group
        -----------------------------------------
        | 1) If you do not already, you will need to create a GroupMe account
        |    since this is what MQTTTasky will use to allow you to schedule
        |    tasks. You may sign up for groupme `here <https://web.groupme.com/signup>`_.
        |
        | 2) Afer registering, login. You will need to create at least one group
        |    to which you will add your GroupMe bot after having created it. For
        |    help with creating a group, see `this page <https://support.microsoft.com/en-us/office/how-do-i-start-a-group-in-groupme-d7488e15-4429-43ff-85fa-a5c7775305e2>`_.
        |
        
        Creating your GroupMe bot
        -------------------------
        | 1) First, register a developer account after logging in at
        |    (https://dev.groupme.com/).
        |
        | 2) After your are logged in, click the 'Bots' link in the main site
        |    navigation or visit (https://dev.groupme.com/bots).
        |
        | 3) Click "Create Bot", and select thr group to which it
        |    will belong and name it. You will not need to enter
        |    a callback URL and you may give the bot an avatar
        |    by entering a public image URL.
        |
        | 4) After having created your bot, it will be visible on the page at
        |    (https://dev.groupme.com/bots).
        |
        | 5) Copy your bot's ID, as well as the Group ID to which it belongs.
        |    Finally, find the 'Access Token' link in the main site navigation
        |    and copy it as well. You will need all of this information shortly.
        |
        
        Setting up a Mosquitto broker
        ------------------------------
        | MQTTTasky requires to be connected to an MQTT broker which uses
        | authentication. The broker can be hosted on another computer or
        | Raspberry Pi. It is not recommended to host the broker on the same Pi
        | as MQTTTasky will be running on. To set up a Mosquitto broker on a
        | Raspberry Pi, please refer to `these instructions <https://medium.com/@eranda/setting-up-authentication-on-mosquitto-mqtt-broker-de5df2e29afc>`_.
        |
        | Please note while following along with the instructions above, that
        | there are a couple of descrepancies. In the first step, you will have
        | to change the line
        
        .. code:: bash
        
            sudo wget http://repo.mosquitto.org/debian/mosquitto-wheezy.list
        
        | to the following:
        
        .. code:: bash
        
            sudo wget http://repo.mosquitto.org/debian/mosquitto-buster.list
        
        | Furthermore, the line that says
        
        .. code:: bash
        
            sudo stop mosquitto
        
        | in step 2 should instead read:
        
        .. code:: bash
        
            sudo systemctl stop mosquitto
        
        | Finally, please record the username and password you used in this
        | configuration as you will need it when configuring MQTTTasky.
        
        Configure MQTTTasky
        -------------------
        | After having completed the above setup, you are ready to start the
        | mqtttasky_groupme program. This may be done simply by entering:
        
        .. code:: bash
        
            mqtttasky_groupme
        
        | On first launch, you will be prompted to enter your GroupMe information
        | as well as your MQTT broker and authentication information. You should
        | have already recorded these. If you are unsure of your broker's port
        | number, it is likely 1883 and if it is hosted on a Linux machine, the
        | IP address can be found using the 'ifconfig' command (or 'ipconfig' on 
        | Windows). If the configuration is successful, you will see similar
        | output to that below:
        
        .. code:: bash
        
            [ MQTT Client ] Connected to broker.
        
        
            #######################
            # Bot: Tarnoff Bot
            # Group: IoT Dev Server
            # Status: Listening
            #######################
        
        | Note that you can break out of the program using Ctrl-C. Any time you
        | need to re-run the configuration, you may enter the command:
        
        .. code:: bash
        
            mqtttasky_groupme_config
        
        
        MQTTTasky: Status lights, notifications, and usage
        ##################################################
        
        Status lights and notifications
        -------------------------------
        | First you will notice that MQTTTasky's MQTT client has connected to
        | the broker. Once the broker is connected, MQTTTasky will start
        | listening for messages every 4 seconds.
        |
        | Each time the program successfully retrieves the messages, the second 
        | (yellow) LED will blink on and off.
        |
        | Each time a message retrieval fails, the first (red) LED will blink on
        | and off.
        |
        | Each time a new message is discovered, the third (green) LED will blink
        | on and off several times.
        |
        | Each time a new response is sent back from the bot, the second (yellow)
        | LED will blink on and off several times.
        |
        | Finally, when a notification is being shown and the MQTT client is
        | publishing data, all three lights will blink several times in a sequence.
        | Additionally, MQTTTasky will display the task notification in a graphical
        | window and read the task information aloud using simple_google_tts. Every
        | time a task notification is published, the payload is encrypted using
        | Fernet encryption and the key provided during the configuration of
        | mqtttasky_groupme. This key can be used to create a Fernet cipher in other
        | MQTT clients on the network so that they may decrypt the payload. Included
        | in the 'node_mqtttasky_pi_client' directory is an example of such a client
        | in Node.js. It's instructions can be found in a separate readme file within
        | that directory.
        
        Usage
        ------
        | The MQTTTasky bot will make it fairly clear what you need to do to create
        | a task, however, other options, such as resetting task data or deleting
        | all scheduled tasks are available. The usage for communicating with the
        | bot is as follows:
        |
        | MQTTasky Usage
        | ===============================
        | - Initiate a new task:
        | 'Schedule task'
        | 'Schedule task <title> with description <description>'
        | 
        | - Date and time:
        | MQTTTasky will let you know how
        | to enter date or time when prompted.
        | If the year is not provided in a date
        | string, the current year is assumed.
        |
        | Time strings ending in AM or PM are
        | automatically converted into 24-hr
        | format.
        |
        | - Notifications:
        | Notifications are specified by a unit
        | of time before the time of the task.
        | You may use the following units of
        | time:
        |
        | Minutes:
        | E.g. '15 minutes before'
        | Hours:
        | E.g. '15 hours before'
        | Days:
        | E.g. '15 days before'
        | Weeks:
        | E.g. '15 weeks before'
        |
        | - Reset:
        | If you want to cancel or restart the
        | creation of a task, use the command:
        | '/reset'
        | 
        | - Delete:
        | To delete all active tasks:
        | '/deleteall'
        | 
        | - Bonus:
        | Ask bot to tell a joke or proverb.
        
        MQTT Topic Details
        ##################
        | The MQTT topic to which MQTTasky publishes its encrypted payloads
        | is pub/tasks. The first topic level denotes published data. The
        | second topic level denotes that task data is being published.
        | The task data published is a message designed to be read over a
        | speaker using TTS. Since a payload is published by the scheduler
        | when a notification is set to occur, this allows subscribed MQTT
        | clients to display and/or speak the notification when it is
        | received.
        |
        | Since payloads are encrypted using Fernet encryption, the symmetric
        | key provided during the initial mqtttasky_groupme configuration can
        | be used by clients to implement Fernet decryption tokens to decrypt
        | the payloads which can then be decoded to UTF-8 strings.
        
        MQTT Encryption
        ###############
        
        Fernet (symmetric encryption)
        -----------------------------
        | MQTTTasky uses the Python Fernet class from cryptography.fernet.
        | This class is popular because of its ease of use, and the security
        | it offers for the lightweight encryption/decryption that is needed
        | in IoT.
        |
        | The algorithm used in Fernet is AES using CBC mode with signing
        | using HMAC and SHA256. Thus Fernet not only encrypts/decrypts but
        | allows for the authentication of messages to ensure integrity
        | (`McBride, 2020 <https://www.pythoninformer.com/python-libraries/cryptography/fernet/>`_).
        |
        
        CBC
        ===
        | In cipher block chaining (CBC), plaintext blocks get XORed with
        | previous ciphertext blocks prior to the encryption process. That
        | is why it is referred to as block chaining, because each ciphertext
        | block depends on ever processed plaintext block at each that moment.
        | This preserves the integrity of the data
        | (`Block cipher mode of operation, 2020 <https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_block_chaining_(CBC)>`_).
        |
        
        HMAC
        ====
        | Hashing for Message authentication (HMAC) applies a hash function
        | over the data and the symmetric key. HMAC using SHA256 is the part
        | of Fernet that ensures the authenticity and integrity of the message
        | (`John C. Villanueva, 2016 <https://www.jscape.com/blog/what-is-hmac-and-how-does-it-secure-file-transfers>`_).
        |
        | As Villanueva (`2016 <https://www.jscape.com/blog/what-is-hmac-and-how-does-it-secure-file-transfers>`_) points out, one advantage of using HMAC for data
        | transfer is that hash functions create a fixed-length digest
        | regardless of the arbitrary length of the message hashed; this
        | results in mitigating the amount of bandwidth needed to transfer
        | data over a network.
        
        Fernet Key Format
        =================
        | Key generation using the cryptography.fernet library's Fernet class
        | renders a 32-byte key which is actually a composite of two 16-byte
        | keys. The first 16 bytes being a signing key used to sign the HMAC
        | and the second 16 bytes being a private key used by the encryption
        | (`McBride, 2020 <https://www.pythoninformer.com/python-libraries/cryptography/fernet/>`_).
        | 
        
        Fernet Token Format
        ====================
        | The Fernet token used in the Fernet class consists of:
        |    • Version, 1 byte - the only valid value currently is 128.
        |    • Timestamp 8 bytes - a 64 bit, unsigned, big-endian integer
        |    that indicates when the ciphertext was created. Time is
        |    represented as the number of seconds since the start of Jan 1,
        |    1970, UTC.
        |    • IV 32 bytes - the 128 bit Initialization Vector used in AES
        |    encryption and decryption.
        |    • Ciphertext - the encrypted version of the plaintext message. This is
        |    encrypted using AES, in CBC mode, using the encryption key section
        |    of the Fernet key. The ciphertext is padded to be a multiple of 128
        |    bits, which is the AES block size, using the PKCS7 padding algorithm.
        |    This menas that the ciphertest will always be a multiple of 16 bytes
        |    in length, but the padding will be automatically removed when the
        |    data is decrypted.
        |    • HMAC - a 256-bit HMAC of the concatenated Version, Timestamp, IV,
        |    and Ciphertext fields. The HMAC is signed using the signing key
        |    section [of the] Fernet key.
        |    (`McBride, 2020 <https://www.pythoninformer.com/python-libraries/cryptography/fernet/>`_).   
        |
        | Once the HMAC has been calculated using the binary data from the Version,
        | Timestamp, IV, and Ciphertext, the entire token is encoded in Base64
        | encoding (`McBride, 2020 <https://www.pythoninformer.com/python-libraries/cryptography/fernet/>`_). According to Base64 (`2020 <https://developer.mozilla.org/en-US/docs/Glossary/Base64>`_), this encoding
        | method is used to encode binary data which may need to be transferred to
        | and stored on media designed to handle ASCII. This is a convenient format
        | for the Web since it would allow binary data to be represented within a
        | URL as ASCII text. This encoding does come at a price -- increased size.
        | Every Base64 digit represents exactly 6 bits of data. Base64 can increase
        | the size of a string by as much as ~33 percent (`Base64, 2020 <https://developer.mozilla.org/en-US/docs/Glossary/Base64>`_).
        
        
        Node.js MQTT client for reading task notifications
        ##################################################
        
        | In the `node_mqtttasky_pi_client <https://github.com/haasr/mqtttasky_groupme/tree/master/node_mqtttasky_pi_client>`_,
        | directory of this repository is a Node.js client which can be configured
        | to use the mqtttasky_groupme client's Fernet key to decrypt the message
        | payloads published by MQTTasky and read them aloud using
        | simple_google_tts. See the separate README file `on this page <https://github.com/haasr/mqtttasky_groupme/tree/master/node_mqtttasky_pi_client>`_ for details
        | about pacakges used, setup, and usage.
Platform: UNKNOWN
Classifier: Intended Audience :: Other Audience
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
