diff --git a/.gitignore b/.gitignore
index ac161f1..00aa5ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,10 +8,7 @@ terraform/terraform
terraform/terraform.exe
#JSON cloud configuration file
-MicroPython/src/aws_config.json
-MicroPython/src/kaa_config.json
-MicroPython/src/config.json
-MicroPython/src/thingsboard_config.json
+MicroPython/src/*.json
# Python cache files
*.pyc
diff --git a/Blynk/Blynk_dashboard.png b/Blynk/Blynk_dashboard.png
new file mode 100644
index 0000000..ac3bb7f
Binary files /dev/null and b/Blynk/Blynk_dashboard.png differ
diff --git a/Blynk/README.md b/Blynk/README.md
new file mode 100644
index 0000000..980bbd2
--- /dev/null
+++ b/Blynk/README.md
@@ -0,0 +1,58 @@
+# Set up account and device on Blynk cloud platform
+The instruction walks you through the process of creating your own IoT device in just a few steps.
+
+An example web dashboard that might be created can look like this:
+![Example dashboard](Blynk_dashboard.png "KaaIoT dashboard")
+
+## What is Blynk
+[Blynk](https://blynk.io/) is a cloud service provider allowing for building and managing connected hardware: device provisioning, sensor data visualization, remote control with mobile and web applications, over-the-air firmware updates and much more.
+
+## Installation
+
+### Install requirements
+
+After you've created virtual environment, your current directory should be "iot-starter"
+
+```
+pip install pyserial cryptography click future pyelftools setuptools
+pip install -r Blynk/requirements.txt
+```
+
+## Set up Blynk account
+
+### 1. Create account
+
+First, you need to create an account on Blynk cloud website: [blynk.cloud](https://blynk.cloud/dashboard/register). Follow standard registration procedure providing your email and then activating the account.
+
+### 2. Creating template and your device
+
+After you first log in into your new account on Blynk,Console you'll be probably prompted with a quickstart device. Please close the window as we're going to do it manually.
+
+#### **Template**:
+
+Template will be used for creating your new IoT-Starter device.
+
+ 1. On the left side pane search for **"Templates"** option.
+ 2. Click on **"+ New Template"** with the name and description of your choice. Make sure to use hardware **"ESP32"** and connection type **"WiFi"**. After creating the template you can modify it further adding an image, metadata etc.
+ 3. Now you need to create two **"Datastreams"** that are responsible for accepting telemetry data (temperature and humidity) from our device. To do that go to:
+ **"Datastreams" --> "+ New Datastream" --> "Virtual Pin"
**
+ Please make two virtual pin datastreams for temperature and humidity. **Please note** which pin is responsible for each telemetry type (only number matters, so if you're assigning **V0** to temperature, the pin responsible for the temperature telemetry is no. **0**). Make sure that the **"Data Type"** is set to **"Double"**. You can also add **"Units"** to the pins (Celsius for the temperature and percentage for the humidity) - it is optional though. Please also adjust the **min** and **max** value for each pin (0 - 100 for the humidity and for example 10 - 40 for the temperature) as well as check the **"Thousands seperator"** option.
+ 4. After creating both virtual pins you can set up a web dashboard after clicking **"Web dashboard"** option. (**"Mobile dashboard"** can be only created in **"Blynk IoT"** mobile app.)
+ 5. Save the changes made to the template.
+
+#### **Device**:
+
+Device will be created from already created template, so all you need to do is:
+
+ 1. Click on the left side pane **"Search"** --> **"+ New Device"** --> **"From template"**
+ 2. Select your template and give some meaningful name to your device.
+ 3. Click on the created device and go to **"Device info"** and on the right side look for **"BLYNK_AUTH_TOKEN"**. It should look like this:
+ ```
+ #define BLYNK_AUTH_TOKEN "";
+ ```
+ Copy this long sequence as you will need it in a moment.
+
+After all steps above you should have saved three things:
+ - Virtual pin for temperature
+ - Virtual pin for humidity
+ - Device auth token
diff --git a/Blynk/requirements.txt b/Blynk/requirements.txt
new file mode 100644
index 0000000..d01f404
--- /dev/null
+++ b/Blynk/requirements.txt
@@ -0,0 +1 @@
+-r ./../MicroPython/requirements.txt
\ No newline at end of file
diff --git a/KAA/Kaa_dashboard.png b/KAA/Kaa_dashboard.png
index 0d81172..455dcef 100644
Binary files a/KAA/Kaa_dashboard.png and b/KAA/Kaa_dashboard.png differ
diff --git a/KAA/README.md b/KAA/README.md
index 33a1b7d..2811a91 100644
--- a/KAA/README.md
+++ b/KAA/README.md
@@ -5,79 +5,11 @@ An example dashboard that might be created can look like this:
![Example dashboard](Kaa_dashboard.png "KaaIoT dashboard")
## What is KaaIoT
-KaaIoT is a cloud service provider allowing for device management, data collection and visualization. You can create a powerful dashboard in a matter of seconds. It's free of charge with a limit of up to 5 devices.
-
-## Requirements
-
-### Python 3, PIP
-Python can be downloaded from this [website](https://www.python.org/downloads) (in case of using [Anaconda environment](https://www.anaconda.com/products/individual), please skip this part and refer to "**Installation**" section). The Python version required for this project is: either 3.6 or 3.7 (preferably). Please follow installation instructions from their website.
-After installation, you can check if it is installed correctly by typing the following commands in your terminal:
-
-* Linux
-```bash
-python3 --version
-pip3 --version
-```
-If python3 is not recognized, try "python"
-
-* Windows:
-```bash
-python --version
-pip --version
-```
+[KaaIoT](https://www.kaaiot.com/) is a cloud service provider allowing for device management, data collection and visualization. You can create a powerful dashboard in a matter of seconds. It's free of charge with a limit of up to 5 devices.
## Installation
-### 1. Create virtual environment:
-First, you need to create virtual environment (either with python venv module or anaconda-python):
-
-Note, that **"ENV_NAME"** is the name of the environment you’re creating.
-
-Enter main directory of the project (iot-starter):
-```bash
-cd iot-starter
-```
-
-* For anaconda (either in terminal - Linux or anaconda prompt - Windows):
- ```
- conda create --name ENV_NAME python=3.7 pip
- ```
-
-* For venv:
- * Linux:
- ```
- python3 -m venv ENV_NAME
- ```
-
- * Windows:
- ```
- python -m venv ENV_NAME
- ```
-
-Next, you should activate it. This step is platform dependent:
-#### Windows
-* For anaconda:
- ```
- conda activate ENV_NAME
- ```
-
-* For venv:
- ```
- ENV_NAME/Scripts/activate.bat
- ```
-
-#### Linux/ Mac OS
-* For anaconda:
- ```
- conda activate ENV_NAME
- ```
-
-* For venv:
- ```
- source ENV_NAME/bin/activate
- ```
-
-### 2. Install requirements
+### Install requirements
After you've created virtual environment, your current directory should be "iot-starter"
diff --git a/MicroPython/README.md b/MicroPython/README.md
index 8819511..4789127 100644
--- a/MicroPython/README.md
+++ b/MicroPython/README.md
@@ -39,7 +39,7 @@ Open the project MicroPython with PyCharm and mark *src* and *ulib_mocks* direct
## Cloud service provider:
-### - KAA
+### KAA
Make sure that your KAA cloud is configured. For more information please go to README in "KAA" directory [here](../KAA/README.md).
By now, you should have four things:
@@ -48,7 +48,9 @@ By now, you should have four things:
- username
- password
-### - AWS
+---
+
+### AWS
Make sure that your AWS cloud is configured. For more information please go to
README in "terraform" directory [here](../terraform/README.md).
@@ -56,7 +58,9 @@ If you already have configured AWS infrastructure, make sure that:
- terraform exists either in ".terraform" directory or installed through the package manager
- you have configured ssh connections with AWS (aws configure)
-### - ThingsBoard
+---
+
+### ThingsBoard
Make sure your ThingsBoard server is configured. For more information please go to README in "ThingsBoard" directory [here](../ThingsBoard/README.md)
Now we will make use of credentials we have saved in previous steps:
@@ -83,8 +87,18 @@ You'll need to also provide new credentials for your device:
After you execute the script, you should see "Provisioning successful!" message. If something went wrong, please try again, validate your provision keys and make sure that the device you're trying to register is not already taken (both client ID and its name).
+---
+
+### Blynk
+Make sure that your Blynk cloud is configured. For more information please go to README in "Blynk" directory [here](../Blynk/README.md).
+
+By now, you should have three things:
+ - Virtual pin for temperature
+ - Virtual pin for humidity
+ - Device auth token
+
-### Basic Setup of the ESP32
+## Basic Setup of the ESP32
To set up a new board or flash the old one.
Make sure that your cloud is configured and in case of using **AWS** make sure that your computer has AWS credentials.
@@ -112,7 +126,7 @@ After finding the correct port, execute:
```bash
python scripts/upload_all.py -p -c -s
```
-where \ is your chosen cloud service provider (KAA, AWS or THINGSBOARD).
+where \ is your chosen cloud service provider (KAA, AWS, THINGSBOARD or BLYNK).
where \ is your currently used sensor (DHT11, DHT22 or BME280). Defaults to DHT22.
After flashing the board please reset it using button EN button.
diff --git a/MicroPython/scripts/cloud_credentials.py b/MicroPython/scripts/cloud_credentials.py
index 4a15a61..8f997c7 100644
--- a/MicroPython/scripts/cloud_credentials.py
+++ b/MicroPython/scripts/cloud_credentials.py
@@ -4,17 +4,17 @@
from common.cloud_providers import Providers
from common.utilities import file_exists
-KAA_CONFIG_SRC_PATH = 'src/kaa_config.json'
-THINGSBOARD_CONFIG_SRC_PATH = 'src/thingsboard_config.json'
+CLOUD_CONFIG_PATH = "src/{}_config.json"
def set_credentials(cloud):
"""
Asks user for credentials for cloud similar to "awscli"
"""
+ cloud_config_path = CLOUD_CONFIG_PATH.format(cloud.lower())
if cloud == Providers.KAA:
- if file_exists(KAA_CONFIG_SRC_PATH):
- with open(KAA_CONFIG_SRC_PATH, 'r', encoding='utf8') as infile:
+ if file_exists(cloud_config_path):
+ with open(cloud_config_path, 'r', encoding='utf8') as infile:
config = json.load(infile)
else:
config = {}
@@ -39,12 +39,12 @@ def set_credentials(cloud):
if password:
config['kaa_password'] = password
- with open(KAA_CONFIG_SRC_PATH, 'w', encoding='utf8') as outfile:
+ with open(cloud_config_path, 'w', encoding='utf8') as outfile:
json.dump(config, outfile)
elif cloud == Providers.THINGSBOARD:
- if file_exists(THINGSBOARD_CONFIG_SRC_PATH):
- with open(THINGSBOARD_CONFIG_SRC_PATH, 'r', encoding='utf8') as infile:
+ if file_exists(cloud_config_path):
+ with open(cloud_config_path, 'r', encoding='utf8') as infile:
config = json.load(infile)
else:
config = {}
@@ -84,7 +84,34 @@ def set_credentials(cloud):
if password:
config['thingsboard_password'] = password
- with open(THINGSBOARD_CONFIG_SRC_PATH, 'w', encoding='utf8') as outfile:
+ with open(cloud_config_path, 'w', encoding='utf8') as outfile:
+ json.dump(config, outfile)
+
+ elif cloud == Providers.BLYNK:
+ if file_exists(cloud_config_path):
+ with open(cloud_config_path, 'r', encoding='utf8') as infile:
+ config = json.load(infile)
+ else:
+ config = {}
+
+ print("Please provide Blynk credentials:")
+ old_auth_token = config.get('blynk_auth_token', None)
+ old_temperature_pin = config.get('blynk_temperature_pin', None)
+ old_humidity_pin = config.get('blynk_humidity_pin', None)
+
+ auth_token = input("Authentication token [{}]: ".format(old_auth_token))
+ temperature_pin = input("Temperature virtual pin [{}]: ".format(old_temperature_pin))
+ humidity_pin = input("Humidity virtual pin [{}]: ".format(old_humidity_pin))
+
+ # If values were not updated; leave the old ones
+ if auth_token:
+ config['blynk_auth_token'] = auth_token
+ if temperature_pin:
+ config['blynk_temperature_pin'] = temperature_pin
+ if humidity_pin:
+ config['blynk_humidity_pin'] = humidity_pin
+
+ with open(cloud_config_path, 'w', encoding='utf8') as outfile:
json.dump(config, outfile)
diff --git a/MicroPython/scripts/common/cloud_providers.py b/MicroPython/scripts/common/cloud_providers.py
index 0976e41..52b4637 100644
--- a/MicroPython/scripts/common/cloud_providers.py
+++ b/MicroPython/scripts/common/cloud_providers.py
@@ -5,11 +5,13 @@ class Providers:
AWS = "AWS"
KAA = "KAA"
THINGSBOARD = "THINGSBOARD"
+ BLYNK = "BLYNK"
@classmethod
def print_providers(cls) -> str:
- return "{}, {}, {}".format(cls.AWS, cls.KAA, cls.THINGSBOARD)
+ return "{}, {}, {}, {}".format(
+ cls.AWS, cls.KAA, cls.THINGSBOARD, cls.BLYNK)
@classmethod
- def get_providers(cls) -> Tuple[str, str, str]:
- return cls.AWS, cls.KAA, cls.THINGSBOARD
+ def get_providers(cls) -> Tuple[str, ...]:
+ return cls.AWS, cls.KAA, cls.THINGSBOARD, cls.BLYNK
diff --git a/MicroPython/scripts/upload_all.py b/MicroPython/scripts/upload_all.py
index 92edc57..8167e77 100644
--- a/MicroPython/scripts/upload_all.py
+++ b/MicroPython/scripts/upload_all.py
@@ -9,9 +9,7 @@
from upload_micropython import erase_chip, flash_micropython
from upload_scripts import flash_scripts
-TERRAFORM_OUTPUT_PATH = "src/aws_config.json"
-KAA_CONFIG_PATH = 'src/kaa_config.json'
-THINGSBOARD_CONFIG_PATH = 'src/thingsboard_config.json'
+CLOUD_CONFIG_PATH = "src/{}_config.json"
CONFIG_OUTPUT_PATH = "src/config.json"
@@ -45,16 +43,12 @@ def save_additional_arguments(cloud_provider, sensor_type):
if __name__ == '__main__':
args = parse_arguments()
+ cloud_config_file_path = CLOUD_CONFIG_PATH.format(args['cloud'].lower())
if args['cloud'] == Providers.AWS:
- if not os.path.isfile(TERRAFORM_OUTPUT_PATH):
+ if not os.path.isfile(cloud_config_file_path):
print("Generating terraform output..")
- save_terraform_output_as_file(TERRAFORM_OUTPUT_PATH)
- cloud_config_file_path = TERRAFORM_OUTPUT_PATH
- elif args['cloud'] == Providers.KAA:
- cloud_config_file_path = KAA_CONFIG_PATH
- set_credentials(args['cloud'])
- elif args['cloud'] == Providers.THINGSBOARD:
- cloud_config_file_path = THINGSBOARD_CONFIG_PATH
+ save_terraform_output_as_file(cloud_config_file_path)
+ elif args['cloud'] in (Providers.KAA, Providers.THINGSBOARD, Providers.BLYNK):
set_credentials(args['cloud'])
else:
raise Exception("Wrong cloud provider! Only: {} are valid".format(
diff --git a/MicroPython/src/cloud/AWS_cloud.py b/MicroPython/src/cloud/AWS_cloud.py
index d4f1e03..b86c9c7 100644
--- a/MicroPython/src/cloud/AWS_cloud.py
+++ b/MicroPython/src/cloud/AWS_cloud.py
@@ -12,7 +12,7 @@
from cloud.cloud_interface import CloudProvider
-class AWS_cloud(CloudProvider):
+class AWSCloud(CloudProvider):
def device_configuration(self, data: list[dict]) -> int:
"""
Configures device in the cloud. Function used as hook to web_app.
diff --git a/MicroPython/src/cloud/Blynk_cloud.py b/MicroPython/src/cloud/Blynk_cloud.py
new file mode 100644
index 0000000..6ae5598
--- /dev/null
+++ b/MicroPython/src/cloud/Blynk_cloud.py
@@ -0,0 +1,177 @@
+import gc
+import logging
+import machine
+import ujson
+import urequests
+import utime
+
+from lib.BlynkLib import Blynk
+
+from common import config, utils
+from common.utils import ConnectionError
+from communication.wirerless_connection_controller import (
+ WirelessConnectionController, get_wireless_connection_controller_instance)
+from controller.main_controller_event import MainControllerEventType
+from cloud.cloud_interface import CloudProvider
+
+
+class InvalidData(Exception):
+ pass
+
+
+class BlynkCloud(CloudProvider):
+ def __init__(self) -> None:
+ if not config.cfg.blynk_auth_token:
+ self.configure_data()
+
+ self.auth_token = config.cfg.blynk_auth_token
+ self.temperature_pin = config.cfg.blynk_temperature_pin
+ self.humidity_pin = config.cfg.blynk_humidity_pin
+ self.blynk = Blynk(self.auth_token)
+
+ def receive_message(self, pins: list, values: list) -> bool:
+ """
+ Checks if value was sent successfully to the server.
+ :param pins: list of virtual pins to check
+ :param values: list of values sent to the server
+ :return bool: True if success, False otherwise
+ """
+ get_url = "http://blynk.cloud/external/api/get?token={}&v{}"
+ for ind, pin in enumerate(pins):
+ server_value = urequests.get(get_url.format(self.auth_token, pin))
+ if round(float(server_value.text), 1) != values[ind]:
+ logging.error("Error sending value to server! Sent value is: {}, received: {}".format(
+ values[ind], float(server_value.text)))
+ return False
+
+ return True
+
+ def device_configuration(self, data: list[dict]) -> int:
+ """
+ Configures device in the cloud. Function used as hook to web_app.
+ :param data: parameters to connect to wifi.
+ :return: Error code (0 - OK, 1 - Error).
+ """
+ logging.debug("Wifi access point configuration:")
+
+ for access_point in data:
+ logging.info("Ssid: {} Password: {}".format(
+ access_point["ssid"], access_point["password"]))
+
+ wireless_controller = get_wireless_connection_controller_instance()
+ try:
+ utils.connect_to_wifi(wireless_controller, data)
+ logging.info(wireless_controller.sta_handler.ifconfig())
+ config.cfg.access_points = data
+ except Exception as e:
+ logging.error("Exception caught: {}".format(e))
+ config.cfg.access_points = config.DEFAULT_ACCESS_POINTS
+ config.cfg.save()
+ return MainControllerEventType.ERROR_OCCURRED
+
+ config.cfg.ap_config_done = True
+ config.cfg.save()
+ machine.reset()
+
+ return 0
+
+ def load_blynk_config_from_file(self) -> dict:
+ """
+ Load configuration of Blynk from file.
+ :return: Configuration in dict.
+ """
+ if utils.check_if_file_exists(config.BLYNK_CONFIG_PATH) == 0:
+ raise Exception("Create kaa_config.json file first!")
+
+ with open(config.BLYNK_CONFIG_PATH, "r", encoding="utf8") as infile:
+ config_dict = ujson.load(infile)
+
+ return config_dict
+
+ def configure_data(self) -> None:
+ """
+ Setup data from blynk_config file and save it to general config file
+ :return: None
+ """
+ logging.debug("Blynk_cloud/configure_data()")
+ blynk_configuration = self.load_blynk_config_from_file()
+
+ config.cfg.blynk_auth_token = blynk_configuration.get(
+ 'blynk_auth_token', config.DEFAULT_BLYNK_AUTH_TOKEN)
+ config.cfg.blynk_temperature_pin = blynk_configuration.get(
+ 'blynk_temperature_pin', config.DEFAULT_BLYNK_TEMPERATURE_PIN)
+ config.cfg.blynk_humidity_pin = blynk_configuration.get(
+ 'blynk_humidity_pin', config.DEFAULT_BLYNK_HUMIDITY_PIN)
+
+ config.cfg.save()
+
+ def _format_data(self, data: dict) -> dict:
+ """
+ Helper function for formatting data to match Blynk expected input
+ :param data: Data in dict to be formatted
+ :return dict: Formatted data
+ """
+ formatted_data = {}
+ for _, (key, values) in enumerate(data.items()):
+ # Unpack outer list and extract values to variables
+ (_, value), = values
+ formatted_data[key] = round(value, 1)
+
+ return formatted_data
+
+ @staticmethod
+ def wifi_connect(sync_time=False) -> WirelessConnectionController:
+ """
+ Connects to WiFi. It is seperate function from utils one, as Blynk doesn't use MQTT Client.
+ :param sync_time: flag if time is synchronized.
+ :return
+ """
+ logging.debug("Blynk_cloud/wifi_connect()")
+
+ try:
+ wireless_controller = get_wireless_connection_controller_instance()
+ utils.connect_to_wifi(wireless_controller,
+ config.cfg.access_points,
+ sync_time)
+
+ while not wireless_controller.sta_handler.isconnected():
+ utime.sleep_ms(1)
+ except ConnectionError as e:
+ logging.error("Error connecting to wifi with status: {}".format(e))
+ try:
+ wireless_controller.disconnect_station()
+ except Exception:
+ logging.error("Error in disconnecting WiFi controller")
+
+ return wireless_controller
+
+ def publish_data(self, data):
+ wireless_controller = BlynkCloud.wifi_connect(sync_time=False)
+
+ data = self._format_data(data)
+ temperature, humidity = data.get(
+ 'temperature', None), data.get('humidity', None)
+ logging.debug("data to send = {}".format(data))
+
+ if temperature is None or humidity is None:
+ raise InvalidData("Invalid data format!")
+
+ self.blynk.connect()
+ self.blynk.run()
+
+ # Send data
+ self.blynk.virtual_write(self.temperature_pin, temperature)
+ self.blynk.virtual_write(self.humidity_pin, humidity)
+
+ gc.collect()
+ utime.sleep(1)
+
+ # Check if operation was successful
+ res = self.receive_message(
+ pins=[self.temperature_pin, self.humidity_pin],
+ values=[temperature, humidity])
+
+ if res:
+ logging.info("Operation successful!")
+
+ wireless_controller.disconnect_station()
diff --git a/MicroPython/src/cloud/KAA_cloud.py b/MicroPython/src/cloud/KAA_cloud.py
index fe8c2a9..d685293 100644
--- a/MicroPython/src/cloud/KAA_cloud.py
+++ b/MicroPython/src/cloud/KAA_cloud.py
@@ -8,7 +8,7 @@
from cloud.cloud_interface import CloudProvider
-class KAA_cloud(CloudProvider):
+class KAACloud(CloudProvider):
def __init__(self) -> None:
self.publish_success_topic = config.cfg.kaa_topic + '/status'
self.publish_error_topic = config.cfg.kaa_topic + '/error'
diff --git a/MicroPython/src/cloud/Things_cloud.py b/MicroPython/src/cloud/Things_cloud.py
index 059727f..c48a561 100644
--- a/MicroPython/src/cloud/Things_cloud.py
+++ b/MicroPython/src/cloud/Things_cloud.py
@@ -10,7 +10,7 @@
from cloud.cloud_interface import CloudProvider
-class ThingsBoard(CloudProvider):
+class ThingsBoardCloud(CloudProvider):
def __init__(self) -> None:
self.request_topic = 'v1/devices/me/rpc/request/+'
self.publish_topic = 'v1/devices/me/telemetry'
diff --git a/MicroPython/src/cloud/cloud_interface.py b/MicroPython/src/cloud/cloud_interface.py
index f5965b5..cac6161 100644
--- a/MicroPython/src/cloud/cloud_interface.py
+++ b/MicroPython/src/cloud/cloud_interface.py
@@ -2,6 +2,7 @@ class Providers:
AWS = "AWS"
KAA = "KAA"
THINGSBOARD = "THINGSBOARD"
+ BLYNK = "BLYNK"
class CloudProvider:
diff --git a/MicroPython/src/common/config.py b/MicroPython/src/common/config.py
index 788c5f8..8a16e07 100644
--- a/MicroPython/src/common/config.py
+++ b/MicroPython/src/common/config.py
@@ -62,7 +62,6 @@
DEFAULT_JSON_HEADER = {'Content-Type': 'application/json'}
# KAA stuff
-KAA_CONFIG_SRC_PATH = 'src/kaa_config.json'
KAA_CONFIG_PATH = "/resources/kaa_config.json"
DEFAULT_KAA_KPC_HOST = "mqtt.cloud.kaaiot.com"
DEFAULT_KAA_APP_VERSION = ""
@@ -86,6 +85,12 @@
DEFAULT_THINGSBOARD_DEVICE_ID = ''
DEFAULT_THINGSBOARD_ATTRIBUTES_EXISTS = False
+# Blynk stuff
+BLYNK_CONFIG_PATH = 'resources/blynk_config.json'
+DEFAULT_BLYNK_AUTH_TOKEN = ''
+DEFAULT_BLYNK_TEMPERATURE_PIN = -1
+DEFAULT_BLYNK_HUMIDITY_PIN = -1
+
class ESPConfig:
"""
@@ -157,6 +162,11 @@ def __init__(self):
self.thingsboard_device_id = DEFAULT_THINGSBOARD_DEVICE_ID
self.thingsboard_attributes_exists = DEFAULT_THINGSBOARD_ATTRIBUTES_EXISTS
+ # Blynk
+ self.blynk_auth_token = DEFAULT_BLYNK_AUTH_TOKEN
+ self.blynk_temperature_pin = DEFAULT_BLYNK_TEMPERATURE_PIN
+ self.blynk_humidity_pin = DEFAULT_BLYNK_HUMIDITY_PIN
+
def load_from_file(self) -> None:
"""
Load configuration of ESP from file.
@@ -258,6 +268,14 @@ def load_from_file(self) -> None:
self.thingsboard_attributes_exists = config_dict.get(
'thingsboard_attributes_exists', DEFAULT_THINGSBOARD_ATTRIBUTES_EXISTS)
+ # Blynk
+ self.blynk_auth_token = config_dict.get(
+ 'blynk_auth_token', DEFAULT_BLYNK_AUTH_TOKEN)
+ self.blynk_temperature_pin = config_dict.get(
+ 'blynk_temperature_pin', DEFAULT_BLYNK_TEMPERATURE_PIN)
+ self.blynk_humidity_pin = config_dict.get(
+ 'blynk_humidity_pin', DEFAULT_BLYNK_HUMIDITY_PIN)
+
if not self.device_uid:
self.device_uid = get_mac_address_as_string()
@@ -327,6 +345,11 @@ def as_dictionary(self) -> dict:
config_dict['thingsboard_device_id'] = self.thingsboard_device_id
config_dict['thingsboard_attributes_exists'] = self.thingsboard_attributes_exists
+ # Blynk
+ config_dict['blynk_auth_token'] = self.blynk_auth_token
+ config_dict['blynk_temperature_pin'] = self.blynk_temperature_pin
+ config_dict['blynk_humidity_pin'] = self.blynk_humidity_pin
+
return config_dict
@staticmethod
diff --git a/MicroPython/src/common/utils.py b/MicroPython/src/common/utils.py
index 9501cc2..9f69994 100644
--- a/MicroPython/src/common/utils.py
+++ b/MicroPython/src/common/utils.py
@@ -15,6 +15,10 @@
NUMBER_OF_NTP_SYNCHRONIZATION_ATTEMPTS = 5
+class ConnectionError(Exception):
+ pass
+
+
def button_irq(p: machine.Pin) -> None:
"""
Callback of interrupt of BOOT button. Resets ESP.
@@ -175,7 +179,7 @@ def get_wifi_and_cloud_handlers(sync_time: bool = False) -> (WirelessConnectionC
except Exception:
logging.error("Error in disconnecting WiFi controller")
- logging.debug("Unable to publish data - no WIFI connection available. Retrying in {}ms".format(
+ logging.debug("Unable to publish data. Retrying in {}ms".format(
config.cfg.data_publishing_period_in_ms))
machine.deepsleep(config.cfg.data_publishing_period_in_ms)
@@ -202,7 +206,7 @@ def connect_to_wifi(wireless_controller: WirelessConnectionController, wifi_cred
wireless_controller.disconnect_station()
except Exception:
pass
- raise Exception(e)
+ raise ConnectionError(e)
if sync_time:
try:
diff --git a/MicroPython/src/controller/main_controller.py b/MicroPython/src/controller/main_controller.py
index dd6fec4..8594644 100644
--- a/MicroPython/src/controller/main_controller.py
+++ b/MicroPython/src/controller/main_controller.py
@@ -1,12 +1,13 @@
import _thread
import logging
+from cloud.Blynk_cloud import BlynkCloud
import machine
import utime
-from cloud.AWS_cloud import AWS_cloud
+from cloud.AWS_cloud import AWSCloud
from cloud.cloud_interface import CloudProvider, Providers
-from cloud.KAA_cloud import KAA_cloud
-from cloud.Things_cloud import ThingsBoard
+from cloud.KAA_cloud import KAACloud
+from cloud.Things_cloud import ThingsBoardCloud
from common import config, utils
from communication import wirerless_connection_controller
from data_acquisition import data_acquisitor
@@ -61,7 +62,7 @@ def __init__(self):
start_data_acquisition=self.start_data_acquisition_hook,
get_status_hook=self.get_status)
- elif config.cfg.cloud_provider == Providers.KAA or config.cfg.cloud_provider == Providers.THINGSBOARD:
+ elif config.cfg.cloud_provider in (Providers.KAA, Providers.THINGSBOARD, Providers.BLYNK):
web_app.setup(
get_measurement_hook=self.get_measurement,
configure_device_hook=self.cloud_provider.device_configuration,
@@ -108,11 +109,13 @@ def get_cloud_provider() -> CloudProvider:
:return: CloudProvider
"""
if config.cfg.cloud_provider == Providers.AWS:
- return AWS_cloud()
+ return AWSCloud()
elif config.cfg.cloud_provider == Providers.KAA:
- return KAA_cloud()
+ return KAACloud()
elif config.cfg.cloud_provider == Providers.THINGSBOARD:
- return ThingsBoard()
+ return ThingsBoardCloud()
+ elif config.cfg.cloud_provider == Providers.BLYNK:
+ return BlynkCloud()
def process_event(self, event: MainControllerEvent) -> None:
"""
@@ -255,10 +258,14 @@ def configure_access_point(self) -> None:
@staticmethod
def test_connection_with_wifi_and_cloud() -> None:
- wireless_controller, mqtt_communicator = utils.get_wifi_and_cloud_handlers(
- sync_time=True)
+ if config.cfg.cloud_provider != Providers.BLYNK:
+ wireless_controller, mqtt_communicator = utils.get_wifi_and_cloud_handlers(
+ sync_time=True)
+
+ mqtt_communicator.disconnect()
+ else:
+ wireless_controller = BlynkCloud.wifi_connect(sync_time=True)
- mqtt_communicator.disconnect()
wireless_controller.disconnect_station()
@staticmethod
diff --git a/MicroPython/src/data_upload/mqtt_communicator.py b/MicroPython/src/data_upload/mqtt_communicator.py
index 734d600..d742ef1 100644
--- a/MicroPython/src/data_upload/mqtt_communicator.py
+++ b/MicroPython/src/data_upload/mqtt_communicator.py
@@ -5,7 +5,7 @@
from umqtt.simple import MQTTClient # micropython-umqtt library
-from cloud.AWS_cloud import AWS_cloud
+from cloud.AWS_cloud import AWSCloud
from cloud.cloud_interface import Providers
from common import config, utils
@@ -22,12 +22,12 @@ def __init__(self,
if cloud_provider == Providers.AWS:
# Secure socket layer MQTT communication
- certificates_existence, aws_certificate, aws_key = AWS_cloud.read_certificates(True)
+ certificates_existence, aws_certificate, aws_key = AWSCloud.read_certificates(True)
if not certificates_existence:
logging.debug("No AWS Certificates, configure_aws_thing()")
- aws = AWS_cloud()
+ aws = AWSCloud()
aws.configure_aws_thing()
- certificates_existence, aws_certificate, aws_key = AWS_cloud.read_certificates(True)
+ certificates_existence, aws_certificate, aws_key = AWSCloud.read_certificates(True)
if not certificates_existence:
raise Exception("Failed to read AWS certificate or key")
diff --git a/MicroPython/src/lib/BlynkLib.py b/MicroPython/src/lib/BlynkLib.py
new file mode 100644
index 0000000..c938a1b
--- /dev/null
+++ b/MicroPython/src/lib/BlynkLib.py
@@ -0,0 +1,277 @@
+# Copyright (c) 2015-2019 Volodymyr Shymanskyy. See the file LICENSE for copying permission.
+
+# MIT License
+
+# Copyright (c) 2015-2018 Volodymyr Shymanskyy
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+__version__ = "1.0.0"
+
+import logging
+import struct
+import time
+import sys
+import os
+
+try:
+ import machine
+ gettime = lambda: time.ticks_ms()
+ SOCK_TIMEOUT = 0
+except ImportError:
+ const = lambda x: x
+ gettime = lambda: int(time.time() * 1000)
+ SOCK_TIMEOUT = 0.05
+
+def dummy(*args):
+ pass
+
+MSG_RSP = const(0)
+MSG_LOGIN = const(2)
+MSG_PING = const(6)
+
+MSG_TWEET = const(12)
+MSG_NOTIFY = const(14)
+MSG_BRIDGE = const(15)
+MSG_HW_SYNC = const(16)
+MSG_INTERNAL = const(17)
+MSG_PROPERTY = const(19)
+MSG_HW = const(20)
+MSG_HW_LOGIN = const(29)
+MSG_EVENT_LOG = const(64)
+
+MSG_REDIRECT = const(41) # TODO: not implemented
+MSG_DBG_PRINT = const(55) # TODO: not implemented
+
+STA_SUCCESS = const(200)
+STA_INVALID_TOKEN = const(9)
+
+DISCONNECTED = const(0)
+CONNECTING = const(1)
+CONNECTED = const(2)
+
+
+class EventEmitter:
+ def __init__(self):
+ self._cbks = {}
+
+ def on(self, evt, f=None):
+ if f:
+ self._cbks[evt] = f
+ else:
+ def D(f):
+ self._cbks[evt] = f
+ return f
+ return D
+
+ def emit(self, evt, *a, **kv):
+ if evt in self._cbks:
+ self._cbks[evt](*a, **kv)
+
+
+class BlynkProtocol(EventEmitter):
+ def __init__(self, auth, tmpl_id=None, fw_ver=None, heartbeat=50, buffin=1024, log=None):
+ EventEmitter.__init__(self)
+ self.heartbeat = heartbeat*1000
+ self.buffin = buffin
+ self.log = log or dummy
+ self.auth = auth
+ self.tmpl_id = tmpl_id
+ self.fw_ver = fw_ver
+ self.state = DISCONNECTED
+ # self.connect() # It has to be done after device configuration
+
+ def virtual_write(self, pin, *val):
+ self._send(MSG_HW, 'vw', pin, *val)
+
+ def send_internal(self, pin, *val):
+ self._send(MSG_INTERNAL, pin, *val)
+
+ def set_property(self, pin, prop, *val):
+ self._send(MSG_PROPERTY, pin, prop, *val)
+
+ def sync_virtual(self, *pins):
+ self._send(MSG_HW_SYNC, 'vr', *pins)
+
+ def log_event(self, *val):
+ self._send(MSG_EVENT_LOG, *val)
+
+ def _send(self, cmd, *args, **kwargs):
+ if 'id' in kwargs:
+ id = kwargs.get('id')
+ else:
+ id = self.msg_id
+ self.msg_id += 1
+ if self.msg_id > 0xFFFF:
+ self.msg_id = 1
+
+ if cmd == MSG_RSP:
+ data = b''
+ dlen = args[0]
+ else:
+ data = ('\0'.join(map(str, args))).encode('utf8')
+ dlen = len(data)
+
+ self.log('<', cmd, id, '|', *args)
+ msg = struct.pack("!BHH", cmd, id, dlen) + data
+ self.lastSend = gettime()
+ self._write(msg)
+
+ def connect(self):
+ if self.state != DISCONNECTED: return
+ self.msg_id = 1
+ (self.lastRecv, self.lastSend, self.lastPing) = (gettime(), 0, 0)
+ self.bin = b""
+ self.state = CONNECTING
+ self._send(MSG_HW_LOGIN, self.auth)
+
+ def disconnect(self):
+ if self.state == DISCONNECTED: return
+ self.bin = b""
+ self.state = DISCONNECTED
+ self.emit('disconnected')
+
+ def process(self, data=None):
+ if not (self.state == CONNECTING or self.state == CONNECTED): return
+ now = gettime()
+ if now - self.lastRecv > self.heartbeat+(self.heartbeat//2):
+ return self.disconnect()
+ if (now - self.lastPing > self.heartbeat//10 and
+ (now - self.lastSend > self.heartbeat or
+ now - self.lastRecv > self.heartbeat)):
+ self._send(MSG_PING)
+ self.lastPing = now
+
+ if data != None and len(data):
+ self.bin += data
+
+ while True:
+ if len(self.bin) < 5:
+ break
+
+ cmd, i, dlen = struct.unpack("!BHH", self.bin[:5])
+ if i == 0: return self.disconnect()
+
+ self.lastRecv = now
+ if cmd == MSG_RSP:
+ self.bin = self.bin[5:]
+
+ self.log('>', cmd, i, '|', dlen)
+ if self.state == CONNECTING and i == 1:
+ if dlen == STA_SUCCESS:
+ self.state = CONNECTED
+ dt = now - self.lastSend
+ info = ['ver', __version__, 'h-beat', self.heartbeat//1000, 'buff-in', self.buffin, 'dev', sys.platform+'-py']
+ if self.tmpl_id:
+ info.extend(['tmpl', self.tmpl_id])
+ info.extend(['fw-type', self.tmpl_id])
+ if self.fw_ver:
+ info.extend(['fw', self.fw_ver])
+ self._send(MSG_INTERNAL, *info)
+ try:
+ self.emit('connected', ping=dt)
+ except TypeError:
+ self.emit('connected')
+ else:
+ if dlen == STA_INVALID_TOKEN:
+ self.emit("invalid_auth")
+ print("Invalid auth token")
+ return self.disconnect()
+ else:
+ if dlen >= self.buffin:
+ print("Cmd too big: ", dlen)
+ return self.disconnect()
+
+ if len(self.bin) < 5+dlen:
+ break
+
+ data = self.bin[5:5+dlen]
+ self.bin = self.bin[5+dlen:]
+
+ args = list(map(lambda x: x.decode('utf8'), data.split(b'\0')))
+
+ self.log('>', cmd, i, '|', ','.join(args))
+ if cmd == MSG_PING:
+ self._send(MSG_RSP, STA_SUCCESS, id=i)
+ elif cmd == MSG_HW or cmd == MSG_BRIDGE:
+ if args[0] == 'vw':
+ self.emit("V"+args[1], args[2:])
+ self.emit("V*", args[1], args[2:])
+ elif cmd == MSG_INTERNAL:
+ self.emit("internal:"+args[0], args[1:])
+ elif cmd == MSG_REDIRECT:
+ self.emit("redirect", args[0], int(args[1]))
+ else:
+ print("Unexpected command: ", cmd)
+ return self.disconnect()
+
+import socket
+
+class Blynk(BlynkProtocol):
+ def __init__(self, auth, **kwargs):
+ self.insecure = kwargs.pop('insecure', False)
+ self.server = kwargs.pop('server', 'blynk.cloud')
+ self.port = kwargs.pop('port', 80 if self.insecure else 443)
+ BlynkProtocol.__init__(self, auth, **kwargs)
+ self.on('redirect', self.redirect)
+
+ def redirect(self, server, port):
+ self.server = server
+ self.port = port
+ self.disconnect()
+ self.connect()
+
+ def connect(self):
+ logging.info("Connecting to Blynk cloud...")
+ s = socket.socket()
+ s.connect(socket.getaddrinfo(self.server, self.port)[0][-1])
+ try:
+ s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
+ except:
+ pass
+ if self.insecure:
+ self.conn = s
+ else:
+ try:
+ import ussl
+ ssl_context = ussl
+ except ImportError:
+ import ssl
+ ssl_context = ssl.create_default_context()
+ self.conn = ssl_context.wrap_socket(s, server_hostname=self.server)
+ try:
+ self.conn.settimeout(SOCK_TIMEOUT)
+ except:
+ s.settimeout(SOCK_TIMEOUT)
+ BlynkProtocol.connect(self)
+
+ def _write(self, data):
+ self.conn.write(data)
+ # TODO: handle disconnect
+
+ def run(self):
+ data = b''
+ try:
+ data = self.conn.read(self.buffin)
+ except KeyboardInterrupt:
+ raise
+ except: # TODO: handle disconnect
+ return
+ self.process(data)
+
diff --git a/README.md b/README.md
index 3a55f90..417320b 100644
--- a/README.md
+++ b/README.md
@@ -3,9 +3,10 @@
## Overview
This repository contains the WizzDev mobile IoT application in the "Starter" version. The project is based on ESP32 MCU and one of supported cloud service providers infrastructure. ESP32 is responsible for gathering data from the sensor (in this case DHT22), with a specified period of time, and sending them to the chosen cloud using the MQTT protocol. Depending on the chosen cloud, data can be viewed:
-- AWS: directly on the AWS, or on the dedicated visualization page.
-- KAA: directly on the Kaa on the created dashboard for a device.
-- ThingsBoard: directly on the dashboard in ThingsBoard local page
+- [AWS](https://aws.amazon.com/): directly on the AWS, or on the dedicated visualization page
+- [KAA](https://www.kaaiot.com/): directly on the Kaa on the created dashboard for a device
+- [ThingsBoard](https://thingsboard.io/): directly on the dashboard in ThingsBoard local page
+- [Blynk](https://blynk.io/): directly on the dashboard on mobile app or on the website
The board was programmed using MicroPython, which is a Python implementation for embedded devices. If you are a novice and / or just want to try a solution that works without putting much work into it, we recommend using Kaa cloud which is much faster to set up.
@@ -30,9 +31,27 @@ sudo dnf install git wget bison gperf python python-pip python3-virtualenv pytho
* Windows:
- install [git](https://git-scm.com/downloads)
- - install [python](https://www.python.org/downloads/windows/) (3.6 / 3.7) with pip and virtualenv - no need to install if you've chosen anaconda-python
+ - install [python](https://www.python.org/downloads/windows/) (**3.7 version is required!**) with pip and virtualenv - no need to install if you've chosen anaconda-python
- install drivers for ESP32 from this [link](https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers) - make sure to select Universal Windows Driver
+
+### Python 3, PIP
+Python can be downloaded from this [website](https://www.python.org/downloads) (in case of using [Anaconda environment](https://www.anaconda.com/products/individual), please skip this part and refer to the next section). The Python version required for this project is: either 3.6 or 3.7 (preferably). Please follow installation instructions from their website.
+After installation, you can check if it is installed correctly by typing the following commands in your terminal:
+
+* Linux
+```bash
+python3 --version
+pip3 --version
+```
+If python3 is not recognized, try "python"
+
+* Windows:
+```bash
+python --version
+pip --version
+```
+
Make sure you have access to required hardware:
- **(For AWS only)** Account with ACCESS_CODE and SECRET_CODE - [more info](https://github.com/wizzdev-pl/iot-starter/blob/devel/terraform/README.md#Additional-information-and-help)
@@ -41,6 +60,54 @@ Make sure you have access to required hardware:
- DHT11 or DHT22 sensor with cables (additional 10k pull-up resistor may be needed) or BME280 (IMPORTANT! Default measurement pin for DHT sensors is 27! BME280 uses pins 21 as SCL and 22 as SDA)
- WiFi connection
+### Create virtual environment:
+First, you need to create virtual environment (either with python venv module or anaconda-python):
+
+Note, that **"ENV_NAME"** is the name of the environment you’re creating.
+
+Enter main directory of the project (iot-starter):
+```bash
+cd iot-starter
+```
+
+* For anaconda (either in terminal - Linux or anaconda prompt - Windows):
+ ```
+ conda create --name ENV_NAME python=3.7 pip
+ ```
+
+* For venv:
+ * Linux:
+ ```
+ python3 -m venv ENV_NAME
+ ```
+
+ * Windows:
+ ```
+ python -m venv ENV_NAME
+ ```
+
+Next, you should activate it. This step is platform dependent:
+#### Windows
+* For anaconda:
+ ```
+ conda activate ENV_NAME
+ ```
+
+* For venv:
+ ```
+ ENV_NAME/Scripts/activate.bat
+ ```
+
+#### Linux/ Mac OS
+* For anaconda:
+ ```
+ conda activate ENV_NAME
+ ```
+
+* For venv:
+ ```
+ source ENV_NAME/bin/activate
+ ```
## Cloning repository
@@ -76,6 +143,9 @@ AWS's configuration is handled using terraform. Detailed description of this pro
### **ThingsBoard configuration:**
As ThingsBoard is hosted locally on your device you need to configure it first. Detailed description of the whole procedure is available in "ThingsBoard" directory [here](ThingsBoard/README.md)
+### **Blynk configuration:**
+In order to set up Blynk, you'll need to create manually a device. Detailed description of this procedure is available in the "Blynk" directory [here](Blynk/README.md).
+
---
## **After cloud setup:**
@@ -97,6 +167,8 @@ Log in to your KAA account. From the side pane select "Device management" -> "De
Another way of visualization of the data is to create a dashboard. You can use already created widgets or create custom ones. For more information visit [documentation](https://docs.kaaiot.io/KAA/docs/v1.3.0/Features/Visualization/WD/Dashboards/).
+---
+
## **For ThingsBoard:**
### Device management
@@ -109,6 +181,14 @@ To visualize data you need to create a dashboard. Whole process of setting up da
---
+## **For Blynk:**
+
+### Dashboard
+
+You can view your data on the dashboard in either the Blynk.Console in a "Web Dashboard" or on the mobile app in a "Mobile Dashboard". For each device template you can set your "Web Dashboard" ("Templates" --> \ --> "Web Dashboard" (edit option)) in the Blynk.Console or a "Mobile Dashboard" directly in "Blynk IoT" mobile app.
+
+---
+
## **For AWS:**
### AWS console - IoT Core
diff --git a/ThingsBoard/README.md b/ThingsBoard/README.md
index b72b5f6..5778971 100644
--- a/ThingsBoard/README.md
+++ b/ThingsBoard/README.md
@@ -5,79 +5,11 @@ An example dashboard that might be created can look like this:
![Example dashboard](ThingsBoard_dashboard.png "ThingsBoard dashboard")
## What is ThingsBoard
-ThingsBoard is an open-source IoT platform that enables rapid development, management, and scaling of IoT projects. You can host it locally on your device or use the paid cloud version.
-
-## Requirements
-
-### Python 3, PIP
-Python can be downloaded from this [website](https://www.python.org/downloads) (in case of using [Anaconda environment](https://www.anaconda.com/products/individual), please skip this part and refer to "**Installation**" section). The Python version required for this project is: either 3.6 or 3.7 (preferably). Please follow installation instructions from their website.
-After installation, you can check if it is installed correctly by typing the following commands in your terminal:
-
-* Linux
-```bash
-python3 --version
-pip3 --version
-```
-If python3 is not recognized, try "python"
-
-* Windows:
-```bash
-python --version
-pip --version
-```
+[ThingsBoard](https://thingsboard.io/) is an open-source IoT platform that enables rapid development, management, and scaling of IoT projects. You can host it locally on your device or use the paid cloud version.
## Installation
-### 1. Create virtual environment:
-First, you need to create virtual environment (either with python venv module or anaconda-python):
-
-Note, that **"ENV_NAME"** is the name of the environment you’re creating.
-
-Enter main directory of the project (iot-starter):
-```bash
-cd iot-starter
-```
-
-* For anaconda (either in terminal - Linux or anaconda prompt - Windows):
- ```
- conda create --name ENV_NAME python=3.7 pip
- ```
-
-* For venv:
- * Linux:
- ```
- python3 -m venv ENV_NAME
- ```
-
- * Windows:
- ```
- python -m venv ENV_NAME
- ```
-
-Next, you should activate it. This step is platform dependent:
-#### Windows
-* For anaconda:
- ```
- conda activate ENV_NAME
- ```
-
-* For venv:
- ```
- ENV_NAME/Scripts/activate.bat
- ```
-
-#### Linux/ Mac OS
-* For anaconda:
- ```
- conda activate ENV_NAME
- ```
-
-* For venv:
- ```
- source ENV_NAME/bin/activate
- ```
-
-### 2. Install requirements
+### Install requirements
After you've created virtual environment, your current directory should be "iot-starter"
diff --git a/terraform/README.md b/terraform/README.md
index e28299d..ce20dd7 100644
--- a/terraform/README.md
+++ b/terraform/README.md
@@ -24,23 +24,6 @@ You can check your installation with this command (if the terraform was download
terraform.exe -version
```
-### Python 3, PIP
-Python can be downloaded from this [website](https://www.python.org/downloads) (in case of using [Anaconda environment](https://www.anaconda.com/products/individual), please skip this part and refer to "**Installation**" section). The Python version required for this project is: either 3.6 or 3.7 (preferably). Please follow installation instructions from their website.
-After installation, you can check if it is installed correctly by typing the following commands in your terminal:
-
-* Linux
-```bash
-python3 --version
-pip3 --version
-```
-If python3 is not recognized, try "python"
-
-* Windows:
-```bash
-python --version
-pip --version
-```
-
### Node.js, npm
These requirements are needed to build and bundle visualization. Nodejs can be installed in two ways:
- From the [website](https://nodejs.org/en/download). Npm should be installed automatically along with nodejs.
@@ -99,59 +82,14 @@ If it's the latter, change 2017 to 2015 in above commands.
## Installation
-### 1. Create virtual environment:
-First, you need to create virtual environment (either with python venv module or anaconda-python):
-
-Note, that **"ENV_NAME"** is the name of the environment you’re creating.
+### Install requirements
Enter main directory of the project (iot-starter):
```bash
cd iot-starter
```
-* For anaconda (either in terminal - Linux or anaconda prompt - Windows):
- ```
- conda create --name ENV_NAME python=3.7 pip
- ```
-
-* For venv:
- * Linux:
- ```
- python3 -m venv ENV_NAME
- ```
-
- * Windows:
- ```
- python -m venv ENV_NAME
- ```
-
-Next, you should activate it. This step is platform dependent:
-#### Windows
-* For anaconda:
- ```
- conda activate ENV_NAME
- ```
-
-* For venv:
- ```
- ENV_NAME/Scripts/activate.bat
- ```
-
-#### Linux/ Mac OS
-* For anaconda:
- ```
- conda activate ENV_NAME
- ```
-
-* For venv:
- ```
- source ENV_NAME/bin/activate
- ```
-
-### 2. Install requirements
-
-If You've followed steps, your current directory is "iot-starter"
-
+Run the following commands to install requirements:
```
pip install pyserial cryptography click future pyelftools setuptools
pip install -r requirements.txt