BioZopix Tutoriels

BioZopiX go on walking

Administrator
Odoo Members


Biozopix en marche!

De nouveau re-visité, le concept du podomètre connecté se décline désormais aussi pour les juniors, et surtout propose un tutoriel pour re-fabriquer la 'podo-gourmèt'': Pour les filles...

Mise à jour Odoo

Au passage sur Raspberry (3B+) toujours sur Odoo mais désormais en version 12 avec l'Iot box (POS box améliorée).

En version 11, a été développé un module spécifique pour la formation.

Un serveur Blynk et Node-red sont également intégrés sur les raspberrypis (3 et 0) comme plate-forme à embarquer pour l'interconnexion des objets connectés.

Un exemple d'objet connecté (anémomètre) utilisant la technologie Sigfox fait par ailleurs l'objet d'un petit article sur le site d'Enumea.

Comment remonter la 'montre-à-pied'

Le podogourmètre est une variante de la semelle connectée à base de Wemos D1 mini, une évolution de l'ESP8266, avec un bon nombre d'entrées/sorties digitales et une alimentation intégrée 5V par le micro-USB, mais c'est surtout l'entrée analogique qui nous intéresse.

Le capteur FSR Sensitronics est directement pluggé entre cette entrée A0 et le 3.3V nominal de l'ESP, et en pont de Wheatstone avec une résistance de 1kohm à la masse. C'est tout, avec juste un petit écran de 0,66pouces montés en I2C sur D1 et D2 pour compléter le dispositif.

Odoo - Sample 1 for three columns

Liste de course sur Aliexpress (<20€)

WemosD1 mini (ESP8266-12)

Ecran OLED 48x32

R 1kohm

FSR

lipo 1S

Odoo - Sample 2 for three columns

Shéma électronique

La fiche technique du Wemos est à lire sur la page du constructeur chinois Espressif.

En pré-requis, le Wemos pourra être d'abord testé sous micro-python puis revenir sous la dernière version stable de firmware avec les bonnes librairies sous l'IDE Arduino.

Le sketch utilise notamment la librairie OTA (Over The Air) pour téléverser plus rapidement et sans fil.

Odoo - Sample 3 for three columns

Trouver un boîtier sur Thingiverse

Un boîtier cubique pour l'écran OLED 0.66 est d'abord imprimé grossièrement pour constater que, trop petit pour la carte WEMOS, avec le capot qui ne s'emboîte pas et trop haut, les dimensions peuvent ensuite être adaptées dans l'Openscad fourni ci-dessous.

Ensuite il est possible de donner libre court à votre imagination et adapter n'importe quel boîtier en forme de coeur ou de soleil, etc...

Openscad/Aduino Scripts

A adpater à votre convenance:


height = 17.0;

thickness = 2.0;
fudge = 0.2;

width = 40;
depth = 32;
 
cavity_width = width - (2 * thickness);
cavity_depth = depth - (2 * thickness);
cavity_height = height - thickness + fudge;

hole_diameter = 3;

slit_width = 4.0;
slit_height = 23.0;

// lid
difference() {
    union () {
        translate([-(width / 2.0), 20, 0.0]) cube([width, depth, 2.0]);
        translate([-(cavity_width / 2.0), 22, 2.0]) cube([cavity_width-0.5, cavity_depth-0.5, 1.5]);            
    }
    translate([1, 22 + (cavity_depth / 2), 2.5]) cube(19,8, center = true);
    //rotate([0, 0, 90]) translate([21.9, -12.5, 0]) cube([slit_width, slit_height, 10]);
   // rotate([0, 0, 90]) translate([44.6, -12.5, 0]) cube([slit_width, slit_height, 10]);
}

// base
union() {
    translate([13.5, -(cavity_depth / 2.0), 2]) cube([4.0, cavity_depth, 4.0]);
    translate([-16, -(cavity_depth / 2.0), 2]) cube([4.0, cavity_depth, 2.0]);
    difference () {
        translate([0, 0, height / 2.0]) cube([width, depth, height], center = true);
        translate([0, 0, (cavity_height / 2.0) + thickness]) cube([cavity_width, cavity_depth, cavity_height], center = true);
        translate([1, 0, thickness / 2.0]) cylinder(h = thickness + fudge, r1 = hole_diameter, r2 = hole_diameter, center = true);
        rotate([0, 0, 90]) translate([9, -12.5, 0]) cube([slit_width, slit_height, 5]);
        rotate([0, 0, 90]) translate([-13, -12.5, 0]) cube([slit_width, slit_height, 5]);
        translate([-20, -6, 1]) cube([3, 12, 8]);
        translate([-17.25, 13.0, 4]) cube([7, 3, 4]);        
    }
}

adapté sous Openscad

#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ESP8266WebServer.h>

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space

#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>


#define OLED_RESET 0  // GPIO0
Adafruit_SSD1306 OLED(OLED_RESET);
Adafruit_SSD1306 display(OLED_RESET);
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00011000, B00011000,
  B01111110, B01111110,
  B11111111, B11111111,
  B11111100, B01111111,
  B11111101, B10111111,
  B01111100, B01111110,
  B00111101, B10111100,
  B00011100, B01111000,
  B00001111, B11110000,
  B00000111, B11100000,
  B00000011, B11000000,
  B00000001, B10000000,
  B00000011, B11000000,
  B00001100, B01100000,
  B00110000, B00110100,
  B00011000, B00011000 };

String  etatLed = "OFF";

SimpleTimer timer;
char auth[] = "fca343e8867e490d89d4ca62f6279fd8"; //D1m 591f2140fa5a455880a989631eb32554
char ssid[] = "RpiAP3"; //"Livebox-6896"
char password[] = "password"; //"2615DA7797422E6463C512D495"

ESP8266WebServer server(80);

int   checkInterval = 100000;

int maxforce = 0;
int maxpoids = 0;
int forceReading = 0;
int npas = 0;

String getPage(){
  String page = "<html lang=fr-FR><head><meta http-equiv='refresh' content='0.25'>";
  page += "<title>BioZopiX</title>";
  page += "<style> body { background-color: #ffffff; font-family: Arial, Helvetica, Sans-Serif; Color: #ff0000; }</style>";
  page += "</head><body><h1>Podo-gourmetre</h1>";
  page += "<h3>Podometre / Balance:</h3>";
  page += "<ul><li>Activite : ";
  page += npas;
  page += " pas</li>";
  page += "<progress value='";
  page += npas;
  page += "' max='10000'></progress>";
  page += "<li>Poids max : ";
  page += maxpoids;
  page += " kg</li>";
  page += "<progress value='";
  page += maxpoids;
  page += "' max='100'></progress></ul>";
  page += "<h3>LED / WEMOS</h3>";
  page += "<form action='/' method='POST'>";
  page += "<ul><li>D4 (etat: ";
  page += etatLed;
  page += ")";
  page += "<INPUT type='radio' name='LED' value='1'>ON";
  page += "<INPUT type='radio' name='LED' value='0'>OFF</li>";
  page += "<INPUT type='submit' value='Actualiser'></ul>";
  page += "<svg width='400' height='200'>";
  page += "<ellipse style='fill:#000000' cx='102.77632' cy='32.381577' rx='13.979208' ry='14.917805' />";
  page += "<path style='fill:#ff0000 '";
  page += "d='m 176.92544,60.539474 c 8.71314,-3.820829 7.67627,-4.265559 25.3421,-10.324562 18.60186,-0.819117 44.82172,16.903968 37.54386,42.706141 -13.44431,33.834997 -36.54932,52.212907 -62.41666,66.171057 -26.25224,-17.47546 -51.82417,-35.74462 -63.35527,-70.394742 -2.92967,-23.056157 9.31828,-32.83189 26.28071,-38.482456 12.20175,-0.728541 24.40351,-1.187502 36.60526,10.324562 z'/>";
  page += "<path style='fill:#000000 '";  
  page += "d='m 52.561404,94.328947 c -1.379185,-0.888808 2.76835,-9.991834 10.435256,-23.537518 0,0 2e-6,-3e-6 2e-6,-3e-6 4.577556,-5.683799 10.090921,-12.213 16.258294,-19.243884 4.521315,-1.83189 9.225357,-3.692345 14.087319,-5.58656 0.575751,0.360768 1.153464,0.723228 1.732688,1.087154 3.677325,2.310463 7.259697,4.582127 10.734817,6.818122 5.70888,8.342487 10.80608,16.138364 14.98961,22.887938 10.50659,10.851962 16.88606,18.704778 15.7664,19.921243 -1.12254,1.219593 -9.5216,-4.541605 -21.79414,-14.650233 -4.78207,-6.071894 -10.21702,-13.337624 -15.967388,-21.382692 -1.802708,-1.722784 -3.597132,-3.482892 -5.43804,-5.311518 -0.289679,-0.287746 -0.578516,-0.575207 -0.866391,-0.862154 -2.554228,1.653124 -5.023003,3.222215 -7.500399,4.738001 -5.607313,6.129217 -10.892761,11.668959 -15.653988,16.422783 0,0 -3e-6,3e-6 -3e-6,3e-6 -8.852623,12.093895 -15.407505,19.586416 -16.784037,18.699318 z";
  page += "M0,0m 92.499831,54.468842 c 2.388825,0.343984 1.337833,19.951245 -2.065792,45.186164 0,0 -10e-7,5e-6 -10e-7,5e-6 2.275304,4.116769 4.610865,8.431489 6.96279,12.878709 15.394752,29.10967 26.208292,54.15934 23.682122,55.47505 -2.52322,1.31418 -17.09357,-22.35884 -32.965192,-53.28779 -2.38671,-4.65096 -4.660009,-9.18525 -6.784638,-13.51635 0,0 10e-7,-10e-6 10e-7,-10e-6 4.200772,-27.54662 8.777963,-47.080327 11.17071,-46.735778 z";
  page += "M0,0m 88.148153,101.93141 c 2.589639,0.95077 -1.266741,17.72582 -8.696088,37.91018 -0.105323,0.14528 -0.210953,0.29072 -0.316886,0.43631 -12.791645,17.5808 -24.797897,30.31146 -27.043074,28.66947 -2.245803,-1.64245 6.072982,-16.70053 18.322515,-33.36102 0.102945,-0.14002 0.205864,-0.27974 0.308753,-0.41916 7.023097,-19.17931 14.834898,-34.18664 17.42478,-33.23578 z'/>";
  page += "</svg>";
  page += "<br><br><p><a hrf='http://biozopix.sytes.net'>http://biozopix.sytes.net</p>";
  page += "</body></html>";
  return page;
}

void handleRoot(){
  if ( server.hasArg("LED") ) {
    handleSubmit();
  } else {
    server.send ( 200, "text/html", getPage() );
  }  
}
 
void handleSubmit() {
  // Actualise le GPIO / Update GPIO
  String LEDValue;
  LEDValue = server.arg("LED");
  Serial.println("Set GPIO "); Serial.print(LEDValue);
  if ( LEDValue == "1" ) {
    digitalWrite(BUILTIN_LED, LOW);
    etatLed = "On";
    server.send ( 200, "text/html", getPage() );
  } else if ( LEDValue == "0" ) {
    digitalWrite(BUILTIN_LED, HIGH);
    etatLed = "Off";
    server.send ( 200, "text/html", getPage() );
  } else {
    Serial.println("Err Led Value");
  }
}

void sendSensor(){  
  int l = digitalRead(D4);//D4=GPIO2 Diode bleue sur la carte Wemos
  Blynk.virtualWrite(V0, 255*(1-l));
//  Serial.println();
//  Serial.print("led=");
//  Serial.print(l);

  int f=A0; //capteur FSR sur A0 en pont de résistance avec R0=1kohm
  int forceReading;
  forceReading = analogRead(f)/9.81; // p=m*g

  Serial.print("Force = ");
  Serial.println(forceReading);
    if (forceReading > maxforce)
{
    maxforce=forceReading;
    maxpoids=forceReading*3.14; //à étalonner P=m*g=F/S
   
}
    if (forceReading < maxforce)
{
  npas++;
  maxforce=0;
  maxpoids=0;
}
 Serial.println(maxforce);
 Serial.println(maxpoids);
 Serial.println(npas);

 
  OLED.clearDisplay();
  OLED.setTextWrap(false);
  OLED.setTextSize(1);
  OLED.setTextColor(WHITE);
  OLED.setCursor(0,0);
  OLED.println("Podogourmetre @PP2018");
  OLED.setCursor(0,9);
  OLED.setTextSize(2);
  OLED.println(int(forceReading*3.14));
  OLED.setCursor(25,13);
  OLED.setTextSize(1);
  OLED.println(" kg / pas");
  Blynk.virtualWrite(V5, int(forceReading*3.14));
  OLED.setCursor(90,13);
  OLED.setTextSize(1);
  OLED.println(npas);
  Blynk.virtualWrite(V1, npas);
  OLED.setCursor(40,25);
  OLED.setTextSize(1);
  OLED.println("BioZopiX");
  display.drawBitmap(105, 20,  logo16_glcd_bmp, 16, 16, 1);

  OLED.display(); //output 'display buffer' to screen  
 
}

void blynkCheck() {
  if (WiFi.status() == 3) {
    if (!Blynk.connected()) {
      Serial.println("WiFi OK, connexion Blynk-server...");
      Blynk.connect();

    }
  }
  if (WiFi.status() == 1) {
    Serial.println("No WiFi, mode offline.");

  }
}

void setup()   {

  pinMode(BUILTIN_LED, OUTPUT);         // Led sur Wemos
  Serial.begin(9600);
    server.on("/", handleRoot);
    server.begin();
    Serial.println("HTTP server started");

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
 Serial.println("Wait for WiFi connection.");

  // ... Give ESP 10 seconds to connect to station.
  unsigned long startTime = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000)
  {
    Serial.write('.');
    //Serial.print(WiFi.status());
    delay(500);
  }
  Serial.println();

  // Check connection
  if(WiFi.status() == WL_CONNECTED)
  {
    // ... print IP Address
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  }
  else
  {
    Serial.println("Can not connect to WiFi station. Go into AP mode.");
    
    // Go into software AP mode.
    WiFi.mode(WIFI_AP);

    delay(10);

    WiFi.softAP("wemosD1","password");

    Serial.print("IP address: ");
    Serial.println(WiFi.softAPIP());

    server.on("/", handleRoot);
    server.begin();
    Serial.println("HTTP server started");

  }

//  Blynk.begin(auth, "WIFICORMIER","86365154","biozopix.sytes.net",8442);
//  Blynk.config(auth, "biozopix.sytes.net",8081);
  Blynk.config(auth, IPAddress(192,168,4,1),8080);
//  Blynk.connect();
// check if connected to Blynk server
  if ((WiFi.status() == 3)) {
    Serial.print("\nBlynk server unreachable. Trying once more");
    Blynk.connect();
//    return;
    }
  timer.setInterval(checkInterval, blynkCheck);
      
  timer.setInterval(100L, sendSensor);
    // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialise avec l'addresse I2C  (0x3C pour le 128x32)
// efface le tampon d'écran.
  display.clearDisplay();

 // miniature bitmap display
  display.drawBitmap(0, 10,  logo16_glcd_bmp, 16, 16, 1);
  display.display();
  delay(1000);
  display.drawBitmap(16, 10,  logo16_glcd_bmp, 16, 16, 1);
  display.display();
  display.invertDisplay(true);
  delay(1000);
  display.drawBitmap(32, 10,  logo16_glcd_bmp, 16, 16, 1);
  display.display();
  display.invertDisplay(false);
  delay(1000);
  display.drawBitmap(48, 10,  logo16_glcd_bmp, 16, 16, 1);
  display.display();
  display.invertDisplay(true);
  delay(1000);
  display.drawBitmap(64, 10,  logo16_glcd_bmp, 16, 16, 1);
  display.display();
  display.invertDisplay(false);
  delay(1000);
  display.startscrollright(0x00, 0x0F);
  delay(1500);

 
  display.clearDisplay();

  OLED.begin();


 ArduinoOTA.onStart([]() {
    Serial.println("Start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

 
}


 
void loop()
{
  ArduinoOTA.handle();
  server.handleClient();  

  if (Blynk.connected()) {
  Blynk.run();

  }
 timer.run();
}

Pascal Pinault , sketch Arduino