venerdì 29 novembre 2024

ESP32 logger low power

A seguito del precedente post in questo caso il logger e' stato fatto con una ESP32S3 






Al contrario di Arduino dove i dati erano salvati su SD card qui vengono salvati sulla memoria interna tramite Littefs. Al primo avvio viene cancellato il file dati poi vengono salvati i dati in append dell'ADC, inoltre 

 

E' stato usato il deep sleep tramite RTC. In questo modo la ESP32 effettua un riavvio completo ogni tot secondi..la variabile conta serve come contatore progressivo dei riavvii in modo che al primo ciclo vengano eseguiti specifici. la variabile conta e' dichiarata come RTC_DATA_ATTR in modo da non essere volatile ed essere preservata nella fase di deep sleep

Anche se non precisssimo quando in deep l'RTC continua a funzionare...si setta quindi la data ed ora al primo riavvio e poi si legge il tempo aggiornato ai successivi riavvii. 

 Usando lo sketch della sola lettura analogica di un pin ESP32 consuma circa 19 mA



in deep sleep il consumo crolla al livello delle decine di  microA tanto che la mia schedina non riesce a rilevarlo

 


per usare LittleFs si deve aggiungere il componente in idf_component.yml

dependencies:
joltwallet/littlefs: "==1.14.8"
## Required IDF v

modificare sdkconfig per indicare il file dove sono settate le impostazioni della partizione (in questo caso il file csv)

# Partition Table
#
# CONFIG_PARTITION_TABLE_SINGLE_APP is not set
# CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE is not set
# CONFIG_PARTITION_TABLE_TWO_OTA is not set
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_demo_esp_littlefs.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_demo_esp_littlefs.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table


e creare il corrispondente file 

nvs,      data, nvs,     0x9000,  0x6000,
phy_init, data, phy,     0xf000,  0x1000,
factory,  app,  factory, 0x10000, 1M,
littlefs,  data, spiffs,      ,  0xF0000,

questo il codice finale

include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_sleep.h"
#include "esp_log.h"
#include "driver/rtc_io.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "deep_sleep_example.h"

#include <time.h>
#include <sys/time.h>

#include "driver/gpio.h"
#define PIN GPIO_NUM_35

#include "esp_system.h"
#include "spi_flash_mmap.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_littlefs.h"
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>


#include "driver/adc.h"
#include "esp_adc_cal.h"



/*
#if SOC_RTC_FAST_MEM_SUPPORTED
static RTC_DATA_ATTR struct timeval sleep_enter_time;
#else
static struct timeval sleep_enter_time;
#endif
*/
RTC_DATA_ATTR int conta =0;

struct tm tm;

static void deep_sleep_task(void *args)
{
esp_deep_sleep_start();
}

static void deep_sleep_register_rtc_timer_wakeup(void)
{
const int wakeup_time_sec = 15;
conta = conta + 1;
gpio_set_direction(PIN, GPIO_MODE_OUTPUT);
gpio_set_level(PIN, 0);
vTaskDelay(100);
gpio_set_level(PIN, 1);

struct timeval tv;
char buffer[30];
time_t curtime;
gettimeofday(&tv, NULL);
curtime=tv.tv_sec;
strftime(buffer,30,"%m-%d-%Y %T.",localtime(&curtime));
printf("Orario %s%ld\n",buffer,tv.tv_usec);

esp_adc_cal_characteristics_t adc1_chars;
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_DEFAULT, 0, &adc1_chars);
adc1_config_width(ADC_WIDTH_BIT_DEFAULT);
adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_11);
int adc_value = adc1_get_raw(ADC1_CHANNEL_4);
static const char *TAG = "demo_esp_littlefs";

ESP_LOGI(TAG, "Initializing LittelFS");

esp_vfs_littlefs_conf_t conf = {
.base_path = "/littlefs",
.partition_label = "littlefs",
.format_if_mount_failed = true,
.dont_mount = false,
};

// Use settings defined above to initialize and mount LittleFS filesystem.
// Note: esp_vfs_littlefs_register is an all-in-one convenience function.
esp_err_t ret = esp_vfs_littlefs_register(&conf);

if (ret != ESP_OK)
{
if (ret == ESP_FAIL)
{
ESP_LOGE(TAG, "Failed to mount or format filesystem");
}
else if (ret == ESP_ERR_NOT_FOUND)
{
ESP_LOGE(TAG, "Failed to find LittleFS partition");
}
else
{
ESP_LOGE(TAG, "Failed to initialize LittleFS (%s)", esp_err_to_name(ret));
}
return;
}

size_t total = 0, used = 0;
ret = esp_littlefs_info(conf.partition_label, &total, &used);
if (ret != ESP_OK)
{
ESP_LOGE(TAG, "Failed to get LittleFS partition information (%s)", esp_err_to_name(ret));
}
else
{
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
}

// Use POSIX and C standard library functions to work with files.
// First create a file.
ESP_LOGI(TAG, "Opening file");
FILE *f = fopen("/littlefs/dati.txt", "a");
if (f == NULL)
{
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
fprintf(f,"%s%ld, %i\n",buffer,tv.tv_usec,adc_value);
fclose(f);
ESP_LOGI(TAG, "File written");
ESP_LOGI(TAG, "Reading file");
f = fopen("/littlefs/dati.txt", "r");
if (f == NULL)

{
ESP_LOGE(TAG, "Failed to open file for reading");
return;
}

int c;
while ((c = getc(f)) != EOF)
putchar(c);

//char line[64];
//fgets(line, sizeof(line), f);
fclose(f);

// All done, unmount partition and disable LittleFS
esp_vfs_littlefs_unregister(conf.partition_label);
ESP_LOGI(TAG, "LittleFS unmounted");



printf("conteggio %d\n",conta);
//printf("Minuti: %llu\n",tv.tv_sec);
printf("Stato: %d\n",adc_value);
printf("Enabling timer wakeup, %ds\n", wakeup_time_sec);
ESP_ERROR_CHECK(esp_sleep_enable_timer_wakeup(wakeup_time_sec * 1000000));
}

void app_main(void)
{

gpio_set_direction(PIN, GPIO_MODE_OUTPUT);
gpio_set_level(PIN, 1);

tm.tm_year = 2024 - 1900;
tm.tm_mon = 11;
tm.tm_mday = 27;
tm.tm_hour = 13;
tm.tm_min = 23;
tm.tm_sec =10;

if (conta < 2) {
time_t t = mktime(&tm);
struct timeval now = { .tv_sec = t };
settimeofday(&now, NULL);

static const char *TAG = "esp_littlefs";

esp_vfs_littlefs_conf_t conf = {
.base_path = "/littlefs",
.partition_label = "littlefs",
.format_if_mount_failed = true,
.dont_mount = false,
};

esp_err_t ret = esp_vfs_littlefs_register(&conf);

if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find LittleFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize LittleFS (%s)", esp_err_to_name(ret));
}
return;
}

if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find LittleFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize LittleFS (%s)", esp_err_to_name(ret));
}
return;
}

struct stat st;

if (stat("/littlefs/dati.txt", &st) == 0) {
// Delete it if it exists
unlink("/littlefs/dati.txt");
}
else{
ESP_LOGE(TAG, "File non cancellato");

}
esp_vfs_littlefs_unregister(conf.partition_label);
ESP_LOGI(TAG, "LittleFS unmounted");
}

deep_sleep_register_rtc_timer_wakeup();
xTaskCreate(deep_sleep_task, "deep_sleep_task", 4096, NULL, 6, NULL);
}


 

giovedì 28 novembre 2024

Arduino logger low power

Alla fine ci sono riuscito

La arduino MKR zero e' ormai da un mese che e' rimasta accesa sul tavolo...o meglio si attiva ogni minuto, legge il pin 0, legge lo stato della carica della batteria, scrive sulla Sd card e si addormenta in deep sleep

la batteria da 6600 mAh e' costituita da 18650

 


 

 

#include "ArduinoLowPower.h"
#include <SD.h>
#include <RTCZero.h>

RTCZero rtc;

/* Change these values to set the current initial time */
const byte seconds = 00;
const byte minutes = 05;
const byte hours = 14;

/* Change these values to set the current initial date */
const byte day = 01;
const byte month = 11;
const byte year = 24;


const int chipSelect = SDCARD_SS_PIN;
int i;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  delay(1000);
  SD.begin(chipSelect);

  rtc.begin(); // initialize RTC
  rtc.setHours(hours);
  rtc.setMinutes(minutes);
  rtc.setSeconds(seconds);
  rtc.setDay(day);
  rtc.setMonth(month);
  rtc.setYear(year);

}

void loop() {
  if (i == 60) {
              digitalWrite(LED_BUILTIN, HIGH);
              delay(500);
              digitalWrite(LED_BUILTIN, LOW);
              delay(500);

              int batteria = analogRead(ADC_BATTERY);
              float voltage = batteria * (4.3 / 1023.0);
              if (voltage < 3.9)
                {
                 for (i=1;i<10;i++)
                 {
                  digitalWrite(LED_BUILTIN, HIGH);
                  delay(50);
                  digitalWrite(LED_BUILTIN, LOW);
                  delay(50);
                }
              }
            
              File dataFile = SD.open("data.txt", FILE_WRITE);

              int sensor = analogRead(0);
              String anno = String(rtc.getYear());
              String mese = String(rtc.getMonth());
              String giorno = String(rtc.getDay());
              String ora = String(rtc.getHours());
              String minuto = String(rtc.getMinutes());
              String secondo = String(rtc.getSeconds());

              if (mese.length() == 1) {mese = "0"+ mese;}
              if (giorno.length() == 1) {giorno = "0"+ giorno;}
              if (ora.length() == 1) {ora = "0"+ ora;}
              if (minuto.length() == 1) {minuto = "0"+ minuto;}
              if (secondo.length() == 1) {secondo = "0"+ secondo;}
             
              if (dataFile) {
                dataFile.println(anno+"/"+mese+"/"+giorno+"-"+ora+":"+minuto+":"+secondo+";"+String(sensor)+";"+String(voltage));
                dataFile.close();
                }
              i = 0;
              }
  i++;
  LowPower.sleep(1000);
}

Turn On raspberry via GPIO

 Per accenderere una Raspberry e' sufficiente mettere allo stato zero il pin GPIO3..quindi basta collegare con un cavo (non in maniera permanente) il pin GPIO ed un pin GND


 


 

 

mercoledì 13 novembre 2024

Update Plotly Dash Csv

 

 


from dash import Dash, html, dcc, callback, Output, Input,State
import plotly.express as px
import pandas as pd

import sqlite3
df = pd.read_csv('./sir.csv')


#cnx = sqlite3.connect('winet.db')
#df = pd.read_sql_query("SELECT * FROM sensori", cnx)


app = Dash(__name__)

app.layout = [
html.H1(children='Sensori', style={'textAlign':'center'}),
html.Div([
dcc.Graph(id='graph-content',
figure={
'data': [
{'x': df.Data, 'y': df.Livello,
'type': 'line', 'name': '68'},
],
'layout': {
'title': 'Soggiacenza'
}
}),
dcc.Interval(
id='interval-component',
interval=2*1000,
n_intervals=0
)
])
]

@app.callback(
Output(component_id='graph-content', component_property='figure'),
Input('interval-component', 'n_intervals'), [State('graph-content', 'figure')]
)

def update_graph(n,figure):
df = pd.read_csv('./sir.csv')
figure['data'][0]['x'] = df.Data
figure['data'][0]['y'] = df.Livello
return figure


if __name__ == '__main__':
app.run(debug=True)

 

martedì 5 novembre 2024

Alpine Linux 2024 su IBM A31

Ho provato a far resuscitare un IBM A31 destinato alla discarica. La macchina ha processore P4, 256 Mb di RAM, la batteria CMOS morta ed e' data 2002 (ps non ha trackpad)

La scelta e' caduta su Alpine Linux. Si puo' fare il boot direttamente da USB ed ho installato l'opzione SYS




l'idea era di avere una macchina con GCC ed X con I3 (attenzione che la tastiera del portatile non ha il tasto Windows quindi quando si configura I3 si deve fare la giusta scelta come tasto modificatore)

Questi sono i comandi per la configurazione

apk add --update alpine-sdk

setup-xorg-base

apk add emacs mc

apk add xf86-video-fbdev xf86-video-vesa font-terminus dbus

dbus-uuidgen > /var/lib/dbus/machine-id

rc-update add dbus

apk add i3wm i3status xterm

addgroup luca input

addgroup luca video

startx /usr/bin/i3


il sistema con la sola consolle occupa circa 159 Mb di RAM, il disco fisso da 20 Gb e' occupato per circa il 5%

alla fine e' ancora una macchina usabile



lunedì 4 novembre 2024

Dockerizza Flask

Un esempio semplice per inserire in un container Docker una applicazione Flask

Partiamo da una semplice applicazione che ha un file app.py ed un requirements.txt

Si crea nello stesso folder dei due files precedenti il Dockerfile

---------------------------------------------------------------------------------------------

FROM python:3.8-slim-buster

WORKDIR /python-docker

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt

COPY . .

CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0"]

---------------------------------------------------------------------------------------------

e si effettua la build con

docker build --tag flask-docker .

terminata la build del container

docker run -d -p 5000:5000 flask-docker

la applicazione sara' visibile su localhost:5000

venerdì 1 novembre 2024

Misuratore di torbidita' TS-300B

Gia' siamo partiti male....ordinato su Aliexpress (costato 1/3 rispetto ad Amazon) ed il cavo di collegamento ha 3 pin....

 


 mentre il connettore sulla scheda ha 4 pin (ed ovviamente il cavo non entra)

 


Il problema e' dal lato scheda ... sulla scheda i pin sono nominati ADVG (dall'alto verso il basso) per l'ingresso del TS-300B e GTV per il lato di connessione verso Arduino

 


incrociando le informazioni con altre schede simili il pinout e'

A = analog input

D = soglia digitale level output

V = Power Positive

G = GND

mentre per il lato arduino

G = GND

T = segnale

V = Vcc  (e' un sensore che deve essere alimentato a 5 V)

Il sensore ha due led L2 che mostra la presenza di alimentazione ed il led L1 che si illumina quando si raggiunge la soglia di tordibita'

Il funzionamento e' semplice...da un lato c'e' un led IR e dall'altro un ricevitore...a seconda di quanta luce arriva al ricevitore viene stimata la torbidita'...visto cio' il sensore e' sensibile alla luce ambientale (deve quindi lavorare al buio ancora meglio dentro ad un tubo)


Leggendo ho trovato che questo tipo di sensori vengono usati in lavastoviglie


 

 

 

 

 

CH57x

Volevo costruirmi un controller fisico per VLC con almeno un comando rotativo (volevo utilizzare M5Dial) da usare mentre cerco di suonare pe...