[PYTHON] Allumer / éteindre le Raspberry pi avec Arduino

Pour la communication i2c (smbus, wire.h) entre Arduino et raspberry pi, reportez-vous au forum outre-mer raspberrypi.org. Fait. Je vais omettre l'introduction d'i2c pour raspberry pi.

Une petite explication

Points d'amélioration

code

côté framboise pi

  1. Lisez les paramètres du fichier de paramètres de format json au démarrage 2, lisez les paramètres du côté arduino
  2. S'il y a une différence dans les paramètres, refléter les paramètres 4, échanger des messages dans la boucle principale
  3. Arrêter lorsqu'une commande d'arrêt est reçue dans la boucle principale

main.py


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import smbus
import time
import os
import json

#Obtention d'un bus I2C
bus = smbus.SMBus(1)

#adresse arduino
SLAVE_ADDRESS = 0x04

#Fin de la configuration
CONFIG_END = 0x00

#Pour la confirmation de configuration 0x1*
REQUEST_CONFIG = 0x10
#Pour le temps de sommeil
GET_INO_SLEEP = 0x11
#Pour le temps d'attente lors de l'arrêt de Raspeye
GET_PI_SHUT = 0x12
#Pour le temps d'attente jusqu'à ce que la tarte aux râpes commence
GET_PI_ISW_TIME = 0x13

#Paramètre de configuration 0x2X
CONFIG_SET = 0x20
#Pour le temps de sommeil
SET_INO_SLEEP = 0x21
#Pour le temps d'attente lors de l'arrêt de Raspeye
SET_PI_SHUT = 0x22
#Pour le temps d'attente après le démarrage de Rasppie
#Lors du retour lorsque l'ACC est désactivé
#Heure de début de la tarte Razz lors du retour avec minuterie de chien de garde
SET_PI_ISW_SLEEP = 0x23

#Nombre maximum d'essais lors de la connexion à I2C
I2C_TRY = 5


#Lecture de la configuration à partir du fichier de configuration
def read_conf():
    with open('conf.json', 'r') as f:
        file = f.read()
    return file


#Lire la configuration actuelle de Raspeye
def get_config(ino_add, name):
    TRY = I2C_TRY
    while TRY:
        try:
            tmp_conf = bus.read_byte_data(ino_add, name)
            return tmp_conf
        except IOError as e:
            print "get config IO error"
            TRY -= 1
        except:
            print "get config error"
            raise
    if not TRY:
        raise


#Ecrire la configuration
def set_config(ino_add, cmd1, cmd2, cmd3, cmd4):
    TRY = I2C_TRY
    while TRY:
        try:
            bus.write_i2c_block_data(ino_add, cmd1, [cmd2, cmd3, cmd4])
            time.sleep(4.0)
        except IOError as e:
            print "set config IO error"
            TRY -= 1
        except:
            print "set config error"
            raise
    if not TRY:
        raise


#Pour vérifier l'état d'entrée de l'ACC
def check_state(ino_add):
    TRY = I2C_TRY
    while TRY:
        try:
            reading = int(bus.read_byte_data(ino_add, 0x50))
            print(reading)
            if reading == 5:
                os.system("sudo /sbin/shutdown -h now")
        except IOError as e:
            print "check data IO error"
            TRY -= 1
        except:
            print "check data Unexcepted error"

if __name__ == '__main__':

    #Charger la configuration
    config = json.loads(read_conf())
    set_ino_sleep = int(config["config"]["arduino"]["sleep"])
    set_pi_shut = int(config["config"]["pi"]["shut_wait"])
    set_pi_sleep = int(config["config"]["pi"]["on_sleep_wakeup_time"])

    #Vérifiez l'état actuel des paramètres
    config_ino_sleep = get_config(SLAVE_ADDRESS, GET_INO_SLEEP)
    config_pi_shut = get_config(SLAVE_ADDRESS, GET_PI_SHUT)
    config_pi_sleep = get_config(SLAVE_ADDRESS, GET_PI_ISW_TIME)

    #Changer la configuration s'il y a un changement
    if (config_ino_sleep != set_ino_sleep):
        set_config(SLAVE_ADDRESS, SET_INO_SLEEP, set_ino_sleep, 0x00, 0x00)
        print "set conf set_ino_sleep"

    if (config_pi_sleep != set_pi_sleep):
        set_config(SLAVE_ADDRESS, SET_PI_ISW_SLEEP, set_pi_sleep, 0x00, 0x00)
        print "set conf set_pi_sleep"

    if (config_pi_shut != set_pi_shut):
        set_config(SLAVE_ADDRESS, SET_PI_SHUT, set_pi_shut, 0x00, 0x00)
        print "set conf set_pi_shut"

    #Boucle principale
    while True:
        check_state(SLAVE_ADDRESS)
        time.sleep(1.0)

Côté Arduino

  1. Vérifiez l'entrée de ACC au démarrage, lorsqu'il est allumé, démarrez Raspberry Pi, lorsqu'il est éteint, allez dormir tel quel
  2. Après avoir démarré raspberry pi, modifiez les paramètres de chaque message reçu, écrivez dans l'EEPROM et répondez au message.
  3. Si l'entrée ACC est coupée et que le drapeau de départ de la minuterie du chien de garde n'est pas réglé, mettez-vous en veille.
  4. Pendant le sommeil, réveillez-vous périodiquement en fonction de l'heure définie et démarrez Raspberry Pi.
  5. S'il y a une entrée ACC pendant le sommeil, démarrez raspberry pi

serial_sleep.ino


#include <avr/wdt.h>  //Bibliothèque de minuterie Watchdog
#include <avr/sleep.h> //Bibliothèque de sommeil
#include <Wire.h> //Bibliothèque I2C
#include <EEPROM.h> //L'adresse de la bibliothèque EEPROM est comprise entre 0 et 511(512)

#define LED_PIN (13) //Pour les broches LED
#define ACC_IN (2) //Pour broche d'interruption
#define PI_POWER (12) //Pour le relais de mise sous tension de Raspeye

const int SLAVE_ADDRESS = 0x04; //Adresse I2C

const int CONFIG_END=0x00; //Pour l'état normal

//Les paramètres suivants sont communs à Razpai
//Pour la confirmation de configuration 0x1*
const int REQUEST_CONFIG=0x10;
//Pour le temps de sommeil
const int GET_INO_SLEEP=0x11;
//Pour le temps d'attente lors de l'arrêt de Raspeye
const int GET_PI_SHUT=0x12;
//Temps d'attente jusqu'à ce que l'alimentation puisse être coupée après le démarrage de Raspeye
const int GET_PI_ISW_TIME=0x13;

//Paramètre de configuration 0x2X
const int CONFIG_SET=0x20;
//Pour le temps de sommeil
const int SET_INO_SLEEP=0x21;
//Pour le temps d'attente lors de l'arrêt de Raspeye
const int SET_PI_SHUT=0x22;
//Pour le temps d'attente après le démarrage de Rasppie
//Lors du retour lorsque l'ACC est désactivé
//Heure de début de la tarte Razz lors du retour avec minuterie de chien de garde
const int SET_PI_ISW_SLEEP=0x23;

//Indicateur d'intervalle de sommeil
volatile bool slp_interval_flg;
//Indicateur de mode veille
volatile bool slp_counter_flg=false;
//Indicateur de boucle de sommeil
volatile bool slp_loop_flg=false;
//Compteur d'intervalle de sommeil
volatile int interval_counter;
//Valeur pour l'envoi du statut ACC à Raspeye
volatile int pi_acc_state;
//Pour conserver le message de mode reçu
volatile int message_state;
//Pour maintenir l'état d'arduino
volatile int ino_state;

//Pour l'adresse EEPROM
//Adresse d'enregistrement du temps de sommeil
const int ino_sleep_addr=0;
//Adresse pour spécifier l'heure de sommeil
const int pi_sleep_wakeup_addr=1;
//Adresse de temps d'attente d'arrêt de Raspeye
const int pi_shut_addr=2;

//Fondamentalement, la minuterie se met en veille pendant 4 secondes x le nombre de fois spécifié.
//4 secondes de la minuterie se font dans la partie de réglage de la minuterie du chien de garde
//4 secondes si ce qui suit est spécifié comme 15* 15 =60 secondes
const int count_max=15; 
//Si ce qui précède est spécifié par 15, il peut être spécifié toutes les minutes.
//Pour les trois éléments suivants, la valeur enregistrée dans l'EEPROM est prioritaire.
//Spécifiez l'état initial (en minutes) du temps de sommeil ci-dessous
volatile int wait_minutes=1; 
//Réglage initial du temps d'attente d'arrêt (unité de 10 secondes) de Raspeye
volatile int pi_shut_time=3;
//Spécifiez le temps d'attente (en minutes) après le démarrage de Raspeye
volatile int pi_osw_time=1;

//Variable pour économiser le temps d'attente après le démarrage de Raspeye
volatile long onslp_max_time; 
//Variable pour gagner du temps après le démarrage de Raspeye
volatile long onslp_past_time;
// onslp_max_dépassement de temps
volatile bool counter_switch=false;

//Réinitialisation de l'état
void init_value()
{
  slp_interval_flg=false;
  message_state=0x00;
  slp_counter_flg=false;
}

//Jeu de broches
void init_pins()
{
  pinMode(LED_PIN,OUTPUT);
  pinMode(PI_POWER,OUTPUT);
  pinMode(ACC_IN, INPUT);
}

//Vérifiez l'état de l'ACC au démarrage
void init_state()
{
  if (digitalRead(ACC_IN))
  {
    ino_state=0x00;
    slp_interval_flg=false;
  }else
  {
    ino_state=0x03;
    //Changer le statut ACC
    pi_acc_state=0x05;
  }
}

//Lire la configuration depuis l'EEPROM
void read_rom_config()
{
  wait_minutes=EEPROM.read(ino_sleep_addr);
  if( (wait_minutes <= 0) || (wait_minutes > 250) )
  {
    wait_minutes=1;
  }
  pi_shut_time=EEPROM.read(pi_shut_addr);
  if( (pi_shut_time <= 0) || ( pi_shut_time >250) )
  {
    pi_shut_time=1;
  }
  pi_osw_time=EEPROM.read(pi_sleep_wakeup_addr);
  if( (pi_osw_time <= 0 ) || (pi_osw_time > 250) )
  {
    pi_osw_time=1;
  }
}

//Ecrire la configuration dans l'EEPROM
//Spécifiez l'adresse et la valeur
void set_config(int addr, byte data)
{
  noInterrupts();
  EEPROM.write(addr,data);
  interrupts();
}

//Paramètres de la minuterie de surveillance
void wdt_set()
{
  wdt_reset();
  cli();
  MCUSR = 0;
  //Définir WDCE WDE
  WDTCSR |= 0b00011000;
  //Paramètres WDIE Spécifiez WDIF par incréments de 4 secondes
  WDTCSR =  0b01000000 | 0b100000;
  sei();
}

//Annulation du réglage de la minuterie du chien de garde
void wdt_unset()
{
  wdt_reset();
  cli();
  MCUSR = 0;
  //Paramètres WDCE WDE
  WDTCSR |= 0b00011000;
  //Initialisation de l'état
  WDTCSR =  0b00000000;
  sei();
}

//Appelé au retour par le chronomètre du chien de garde
//Ceci est une minuterie de chien de garde
ISR(WDT_vect)
{
  //Vérifiez l'indicateur du compteur de sommeil
  if(slp_counter_flg)
  {
    //Augmenter le compteur d'intervalles
    interval_counter++;
    //Fin du sommeil si le compteur d'intervalles a atteint le nombre de fois spécifié
    //Appelé toutes les 4 secondes si spécifié toutes les 4 secondes dans les paramètres de l'horloge de surveillance
    // count_max est de 15 et attendez_Si les minutes sont égales à 1, cela se termine si vous restez 1 minute
    if( interval_counter >= (count_max * wait_minutes) )
    {
      //Fin de sommeil
      slp_counter_flg = false;
    }
  }
}


//Changer le drapeau et l'activer en cas d'interruption ACC
void wakeUp()
{
  slp_counter_flg = false;
}

//sommeil arduino
void sleep()
{
  interval_counter = 0;
  //Jeu de minuterie pour chien de garde
  wdt_set();
  //Réglage du mode veille
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
  //Paramètres d'interruption ACC
  //S'il y a une interruption ACC, changez le drapeau et forcez-le à démarrer
  attachInterrupt(0,wakeUp, RISING); 
  //Ensemble d'indicateurs de compteur de sommeil
  slp_counter_flg=true;
  //Boucle jusqu'à ce que l'indicateur du compteur de sommeil soit effacé
  //ISR avec minuterie pour chien de garde(WDT_vect)Est appelé, donc jusqu'à ce qu'il y ait un changement ou une interruption
  while(slp_counter_flg)
  {
    noInterrupts();  //cli();
    sleep_enable();
    interrupts();    //sei();
    sleep_cpu();  //cpu sleep
    sleep_disable();
  }
  //Annulation du réglage de la minuterie du chien de garde
  wdt_unset(); 
  //Annulation du réglage d'interruption ACC
  detachInterrupt(0); 
}



//Recevoir des messages de Raspeye via I2C
void get_message(int n){
  int cmd[4];
  int x = 0;
  while(Wire.available()) {
    cmd[x] = Wire.read();
    x++;
  }
  if ((cmd[0] >= 16) && (cmd[0] < 32)) // 0x10~0x1F get config
  {
    message_state = cmd[0];
  } 
  else if((cmd[0] >= 32) && (cmd[0] < 47)) //0x20~0x2F set config  
  {
    switch (cmd[0])
    {
      case 0x21: //ino_sleep_time (minutes)
      set_config(ino_sleep_addr, cmd[1]);
      read_rom_config(); //reload config
      break;
      case 0x22: //pi shutdown wait time
      set_config(pi_shut_addr, cmd[1]);
      read_rom_config(); //reload config
      break;
      case 0x23: //pi in sleep wakeup time
      set_config(pi_sleep_wakeup_addr, cmd[1]);
      read_rom_config(); //reload config
      break;
    }
  }
  else if ((cmd[0]==0) && (cmd[3]==120))
  {
    toggle();
  }
  else
  {
  }

  if(cmd[0] == 0x50){
    message_state = cmd[0];
  } 
}

//Envoyer un message à Raspeye
void send_message(){
  //when get cmd switch
  switch (message_state) {
   case 0x11: //ino_sleep_time (minutes)
   Wire.write(wait_minutes);
   break;
   case 0x12: //pi shutdown wait time
   Wire.write(pi_shut_time);
   break; 
   case 0x13: //pi in sleep wakeup time 
   Wire.write(pi_osw_time);
   break; 
   case 0x50: //
   Wire.write(pi_acc_state); //send 
   break;  
 }
}

//Fonction de minuterie de veille (veille en secondes)
void wait_time(int t)
{
  volatile unsigned long now = millis();
  volatile unsigned long out_time = (now + 1000* (unsigned long)t);
  if(now < out_time){
    while(millis()< out_time){}
  }
  //Mesures de contre-débordement
  else 
  {
    while(millis() > now){}
    while(millis() < out_time){}
  }
}

//Fonction Raspeye Power ON
void pi_wakeup()
{
  digitalWrite(PI_POWER,HIGH);
  digitalWrite(LED_PIN,HIGH);
}



//Vérifiez le temps de sommeil
void read_time_slp()
{
  onslp_max_time = ( millis()+ 60000 * pi_osw_time );
  onslp_past_time = millis();
  //S'il déborde, le processus sera modifié, alors définissez l'indicateur de commutation.
  if (onslp_max_time > onslp_past_time)
  {
    counter_switch=true;
  }
  else
  {
    counter_switch=false;
  }
}

//test
boolean LEDON = false; 
void toggle(){
  LEDON = !LEDON; //true and false change
  digitalWrite(LED_PIN, LEDON);  
}

//installer
void setup()
{
  //Initialisation
  init_value();
  //Initialisation des broches
  init_pins();
  //Démarrage I2C
  Wire.begin(SLAVE_ADDRESS);
  //Recevoir un message
  Wire.onReceive(get_message); 
  //Envoyer le message
  Wire.onRequest(send_message); 
  //Lire la configuration depuis l'EEPROM
  read_rom_config();
  //Initialisation de l'état, veille sans connexion ACC
  init_state();
  //Attendre un peu
  delay(1000);
}

//Boucle principale
void loop()
{
  //Vérifiez l'état de l'ACC à chaque fois
  int acc = digitalRead(ACC_IN);
  switch(ino_state)
  {
    //Etat initial
    //Enregistrez l'activation et l'état ACC de Raspeye, et passez à l'état normal
    case 0x00:
      pi_wakeup();
      pi_acc_state=0x01;
      ino_state++;
      break;
    //Condition normale
    case 0x01: 
      //ACC est désactivé, l'indicateur d'intervalle de sommeil n'est pas défini
      if( (acc==0) && (!slp_interval_flg) )
      {
        //Pour arrêter la tarte aux râpes
        ino_state++;
      }
      //Indicateur d'intervalle de sommeil uniquement
      // case 0x04:Lorsque ACC est désactivé, l'indicateur d'intervalle de sommeil est activé.
      else if(slp_interval_flg)
      {
        //Vérifiez le drapeau de commutation du compteur
        if(counter_switch)
        {
          //Traitement normal
          //Heure actuelle onslp_max_Plus que du temps ou débordé onslp_past_S'il est inférieur au temps, annulez l'indicateur d'intervalle
          if((millis() > onslp_max_time) || (millis() < onslp_past_time))
          {
            slp_interval_flg = false;
          }
        }
       //Traitement post-débordement
       //Heure actuelle onslp_past_moins de temps et onslp_max_S'il est temps ou plus, annulez l'indicateur d'intervalle
        else
        {
          if( (millis() < onslp_past_time) && (millis() > onslp_max_time) )
          {
            slp_interval_flg = false;
          }
        }
      }
      break;

    //Arrêt de Rasppie
    case 0x02: 
      ino_state++;
      //Changer la valeur de la variable d'état ACC
      pi_acc_state=0x05; 
      //Attendez que la commande d'arrêt soit exécutée
      wait_time(pi_shut_time * 10);
      //Rasppie hors tension
      digitalWrite(PI_POWER,LOW); 
      digitalWrite(LED_PIN,LOW); 
      //Après avoir éteint le relais, laissez la tarte à la râpe attendre correctement jusqu'à ce que la puissance devienne nulle
      wait_time(pi_shut_time * 10);
      break;

    //sommeil arduino
    case 0x03: 
      sleep();
      ino_state++;
      break;

    //Après s'être réveillé du sommeil
    //Vérifiez l'intervalle de sommeil et vérifiez l'état de l'ACC
    case 0x04:
      slp_interval_flg=true;
      //Lire si ACC est désactivé_time_slp();Pour faire attendre la tarte aux râpes pendant le temps spécifié sans s'arrêter
      if(acc==0)
      {
        read_time_slp();
      }
      //Si ACC est activé, revenez comme d'habitude
      else
      {
        slp_interval_flg=false;
      }
      //État initial de l'arduino
      ino_state=0x00;
      break;
  }
}

fichier de configuration

conf.json


{"config": {"pi": {"shut_wait": "3", "on_sleep_wakeup_time": "1"}, "arduino": {"sleep": "1"}}}

schéma

Recommended Posts

Allumer / éteindre le Raspberry pi avec Arduino
Allumez / éteignez votre PC avec Raspberry Pi
Contrôler la mise sous / hors tension du port USB du Raspberry Pi
pigpio sur Raspberry pi
Cython sur Raspberry Pi
Introduction de pyenv sur Raspberry Pi
Utilisez NeoPixel avec la tarte aux framboises
Installez OpenCV4 sur Raspberry Pi 3
Installez TensorFlow 1.15.0 sur Raspberry Pi
Test de la communication UART avec Raspberry Pi
raspberry pi 4 centos7 installer sur docker
Installez ghoto2 sur Raspberry Pi (Remarque)
Procédure d'installation d'OpenCV sur Raspberry Pi
Détecter l'état du commutateur avec Raspberry Pi 3
Installez OpenMedia Vault 5 sur Raspberry Pi 4
L Chika avec Raspberry Pi C #
Construisez wxPython sur Ubuntu 20.04 sur Raspberry Pi 4
Raspberry Pi "Lampe de notification Honwaka" Partie 2
Détectez la "luminosité" en utilisant python sur Raspberry Pi 3!
Démarrage USB sur Raspberry Pi 4 modèle B
Raspberry Pi "Lampe de notification Honwaka" Partie 1
Activer la communication série UART + avec Raspberry Pi
Adafruit Python BluefruitLE fonctionne sur Raspeye.
Accélérez l'apprentissage en profondeur avec le processeur Rasperry Pi 4
Définir l'espace d'échange sur Ubuntu sur Raspberry Pi
Programmation normale avec la programmation Node-RED avec Raspberry Pi 3
Utiliser le capteur Grove avec Raspberry Pi
Installez la version 64 bits du système d'exploitation (bate) sur Raspberry Pi
Installez docker-compose sur le système d'exploitation Raspberry Pi 64 bits
Exécutez un servomoteur en utilisant python sur Raspberry Pi 3
Raspberry Pi "Lampe de notification Honwaka" Partie 3
Exécuter le servomoteur SG-90 avec Raspberry Pi
Construire un environnement OpenCV-Python sur Raspberry Pi B +
Détectez la température à l'aide de python sur Raspberry Pi 3!
Multiplication matricielle sur GPU Raspberry Pi (partie 2)
Comment installer NumPy sur Raspeye
Travailler avec le GPS en Python pour Raspberry Pi 3
Pourquoi detectMultiScale () est lent sur Raspberry Pi B +
Construire un environnement Django sur Raspai (MySQL)
Essayez d'utiliser le code QR avec Raspberry Pi
Détectez les commutateurs magnétiques à l'aide de python sur Raspberry Pi 3!
Profitez du travail électronique avec GPIO de Raspberry Pi
MQTT Radicon Car avec Arduino et Raspberry
Rendre DHT11 disponible avec Raspeye + python (Remarque)
Démarrage de la compilation croisée pour Raspberry Pi Zero sur Ubuntu
Sonnez le buzzer en utilisant python sur Raspberry Pi 3!
Communication série entre Raspberry pi --Arduino Uno (Python)
Afficher la température du processeur toutes les 5 secondes sur Raspberry Pi 4
Connectez-vous à MySQL avec Python sur Raspberry Pi
Construire un environnement de développement Python sur Raspberry Pi
Créer un environnement Arch Linux sur Raspai
Enregistrez la température et l'humidité avec systemd sur Raspberry Pi
Créer un environnement OpenCV4 sur Raspberry Pi à l'aide de Poetry
Exécutez la matrice LED de manière interactive avec Raspberry Pi 3B + sur Slackbot
Qu'est-ce que Raspberry Pi?
GPGPU avec Raspberry Pi
Essayez de déboguer Python sur Raspberry Pi avec Visual Studio.