Grownode - Water Tower Controlled System

by ogghst in Circuits > Microcontrollers

162 Views, 0 Favorites, 0 Comments

Grownode - Water Tower Controlled System

hb2_close_2.jpg
hb2_front.jpg
hb2_controller.png

My attempt to release a Water Tower system using grownode platform.


Features

  • 4 12VDC PWM output (I personally used them for water pump, peltier pump, peltier fan, environmental fan)
  • 4 12VDC Relay output (Lights 1, Lights2, Peltier cell Hot and Cold mode)
  • 2 temperature sensors (using DB18B20)
  • 1 temperature/humidity/pressure sensor (using BME280)
  • 1 capacitive water level sensor

It has an onboard logic to keep the reservoir at desired temperature prior to water it (thus keeping the system on an acceptable temperature range through all the year)

The board is powered with 220V - 12V 10A power adaptor so it can manage quite a lot of power consumption.


Code

The configuration code is contained in components\grownode\boards\bydroboard2.c.

The working logic is onboard, represented by the leaf components\grownode\leaves\gn_hydroboard2_watering_control. Basically it keeps the reservoir at a controlled temperature and starts the watering periodically if the water is within admissible range.

MQTT Messaging is then collected by a page in OpenHAB where I can display the status of the components:

Configure Your Project

Follow the instructions on Install page in order to have a working environment on your PC. After it, you have a preconfigured environment, that has to be personalized for your needs.

You have two files to start:

sdkconfig, in the main project directory. This is where all the instructions to the compiler resides. This is a standard place to put your settings that will enable specific functionalities. You can edit this file using the IDF command idf.py menuconfigin your IDF command shell. browse into component config, you will find a section named grownode: 

Some basic configuration parameters:


  • reset flash at every startup: every time the board is started up, all information stored are wiped out. This is useful when you are testing the board and you want to restart every time with a clean situation. please note that this removes also your provisioning status (wifi SSID and password)
  • enable networking: in order to have all the network related functionalities. in case of local boards or issues with firmware size this will reduce a lot the firware footprint and enhance performances. Dependant parameters are:
  • provisioning transport: how the board will receive wifi credentials at startup. SoftAP means by becoming a local access point, Bluetooth is the other option. Depending on the choice, you will have to use one of the Espressif provisioning apps (at this page)[https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/provisioning/provisioning.html]
  • SoftAP Prefix: the name of the temporary network the board will create to ask for wifi credentials
  • Enable Display: if set, it will start the display driver. the configuration of the display will be taken from LVGL component configuration settings. Note: if you enable display, make sure in cmakelists.txt you have enabled the build of LVGL uncommenting the line set(ENV{LVGL_PATH} "lvgl/lvgl lvgl/lvgl_esp32_drivers")


Configure the Application

In the main folder of the project you will find a main.c file. This is the entry point of the application. Understanding the code requires a knowledge of the C language and it is not the goal of this tutorial.

Here is a standard main application workflow walkthrough:


Define log configuration directives

Done by using the ESP-IDF logging system. Every GrowNode subsystem has his own log tag so it's easy to enable different logging levels depending on what you want to track.


esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("grownode", ESP_LOG_DEBUG);
esp_log_level_set("gn_commons", ESP_LOG_INFO);
esp_log_level_set("gn_nvs", ESP_LOG_INFO);
...
Configure the application parameters

Here the basic code block in a standard wifi configuration:


gn_config_init_param_t config_init = {
    .provisioning_security = true,
    .provisioning_password = "grownode",
    .server_board_id_topic = false,
    .server_base_topic = "/grownode",
    .server_url = "mqtt://mymqttserver.com",
    .server_keepalive_timer_sec = 60,
    .firmware_url = "http://myserver/grownode.bin",
    .sntp_url = "pool.ntp.org"
};

Here's the explanation of those parameters


  • provisioning_security: whether provisioning data shall be encrypted and if yes the use of a proof of possession (password) is required. See esp-idf provisioning manual for details
  • provisioning_password: the proof of possession password you will need to enter in the provisioning mobile app to let the board enter in your wifi network
  • server_url: where to find the MQTT messaging server
  • server_base_topic: the 'address' of the MQTT messages created by the board and the server
  • server_board_id_topic: whether the board shall publish to the MQTT server its unique ID (calculated from MAC address). if true, the topic will be /grownode/ADBC1234 where 'abcd1234' is your board unique ID
  • server_keepalive_timer_sec: how often the board shall publish a keepalive message see API
  • firmare_url: where to search for an updated firmware when the OTA process will start
  • sntp_url: the address of the time server the board will use to sync its clock


Customize Your Code

Obtain the GrowNode configuration handle

This starts the various subsystems like networking, server messaging, provisioning, display, depending on the configuration you choose in previous steps.


gn_config_handle_t config = gn_init(config_init);
Wait for the configuration to be completed

It takes several seconds depending on the actions needed. In this area you can add your custom code that catches the configuration process status


while (gn_get_config_status(config) != GN_CONFIG_STATUS_COMPLETED) {
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    ESP_LOGI(TAG, "grownode startup sequence code: %d",
            gn_get_config_status(config));
}
Create the Node

Once the GrowNode configuration process has ended, you can then start defining your project structure. First step is to obtain a Node handler. This can be seen as the 'tree trunk' where the 'leaves' will be attached.


gn_node_config_handle_t node = gn_node_create(config, "node");
Add leaves

And then you can add your sensors and actuators, that in GrowNode languages are called leaves. Standard leaves code is contained on components/grownode/leaves folder


gn_leaf_config_handle_t lights1in = gn_leaf_create(node, "lights1in", gn_relay_config, 4096);

In this example we have created an handle to a relay leaf, called lights1in, using the config callback gn_relay_config, with a memory space of 4K. Every leaf has his own characteristic and purposes. Some represents sensors, some actuators, and some has the only purpose to implement control logic for other leaves. The relay leaf, for instance, can be reused for multiple actuators in multiple pins. Some others may have limitations due to the specific hardware used.

In order to make a leaf usable you probably have to configure it. The relay leaf need to know what is the GPIO pin attached and the initial status:


gn_leaf_param_init_double(lights1in, GN_RELAY_PARAM_GPIO, 25);
gn_leaf_param_init_bool(lights1in, GN_RELAY_PARAM_STATUS, false);

Some paramaters are stored in the board non volatile storage (NVS) for later use (both ones in this case), so the real effect of this initialization is just on the first board initialization. Once the parameters has been stored in the board, it is ignored.

Please look at the header file of the leaf you want to use to understand the needed parameters.


Start the node

At this point the leaf is ready for the startup. This is made by calling:


gn_node_start(node);

The framework will tell the network that the board is online, publish the board sensor data, start all the leaves callbacks , start the listeners for leaves dialogue (in the relay leaf, this means the relay can be controlled by setting the status parameter).


...And do nothing forever!

Last step, you should implement an infinite loop:


while (true) {
    vTaskDelay(10000 / portTICK_PERIOD_MS);
}