[PYTHON] Power on / off Raspberry pi on Arduino

For i2c communication (smbus, wire.h) between Arduino and raspberry pi, refer to the overseas forum raspberrypi.org. Did. I will omit the introduction of i2c for raspberry pi.

A little explanation

Improvement points

code

raspberry pi side

  1. Read the settings from the json format configuration file at startup 2, read the settings on the arduino side
  2. If there is a difference in the settings, reflect the settings 4, exchange messages in the main loop
  3. Stop when a stop command is received in the main loop

main.py


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

import smbus
import time
import os
import json

#Obtaining an I2C bus
bus = smbus.SMBus(1)

#arduino address
SLAVE_ADDRESS = 0x04

#End of config
CONFIG_END = 0x00

#For config confirmation 0x1*
REQUEST_CONFIG = 0x10
#For sleep time
GET_INO_SLEEP = 0x11
#For waiting time when shutting down Raspberry Pi
GET_PI_SHUT = 0x12
#For waiting time until Raspberry Pi starts
GET_PI_ISW_TIME = 0x13

#Config setting 0x2X
CONFIG_SET = 0x20
#For sleep time
SET_INO_SLEEP = 0x21
#For waiting time when shutting down Raspberry Pi
SET_PI_SHUT = 0x22
#For waiting time after starting Raspberry Pi
#When returning when ACC is off
#Raspberry Pi startup time when returning with the watchdog timer
SET_PI_ISW_SLEEP = 0x23

#Maximum number of trials when connecting to I2C
I2C_TRY = 5


#Read config from config file
def read_conf():
    with open('conf.json', 'r') as f:
        file = f.read()
    return file


#Read the current config from Raspberry Pi
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


#Write config
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


#For checking the input status of 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__':

    #Load config
    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"])

    #Check the current setting status
    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)

    #Change the config if there is a change
    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"

    #Main loop
    while True:
        check_state(SLAVE_ADDRESS)
        time.sleep(1.0)

Arduino side

  1. Check the input of ACC at startup, when on, start raspberry pi, when off, go to sleep as it is
  2. After starting raspberry pi, change the settings for each received message, write to EEPROM, and reply to the message.
  3. If the ACC input is cut off and the start flag by the watchdog timer is not set, go to sleep.
  4. During sleep, wake up periodically according to the set time and start raspberry pi.
  5. If there is an ACC input during sleep, start raspberry pi

serial_sleep.ino


#include <avr/wdt.h>  //Watchdog timer library
#include <avr/sleep.h> //Sleep library
#include <Wire.h> //I2C library
#include <EEPROM.h> //EEPROM library address is 0 to 511(512)

#define LED_PIN (13) //For LED pins
#define ACC_IN (2) //For interrupt pins
#define PI_POWER (12) //For power ON relay of Raspberry Pi

const int SLAVE_ADDRESS = 0x04; //I2C address

const int CONFIG_END=0x00; //For normal state

//The following settings are common to Raspberry Pi
//For config confirmation 0x1*
const int REQUEST_CONFIG=0x10;
//For sleep time
const int GET_INO_SLEEP=0x11;
//For waiting time when shutting down Raspberry Pi
const int GET_PI_SHUT=0x12;
//Waiting time until the power can be turned off after starting Raspberry Pi
const int GET_PI_ISW_TIME=0x13;

//Config setting 0x2X
const int CONFIG_SET=0x20;
//For sleep time
const int SET_INO_SLEEP=0x21;
//For waiting time when shutting down Raspberry Pi
const int SET_PI_SHUT=0x22;
//For waiting time after starting Raspberry Pi
//When returning when ACC is off
//Raspberry Pi startup time when returning with the watchdog timer
const int SET_PI_ISW_SLEEP=0x23;

//Interval flag during sleep
volatile bool slp_interval_flg;
//Sleep mode flag
volatile bool slp_counter_flg=false;
//Sleep loop flag
volatile bool slp_loop_flg=false;
//Sleep interval counter
volatile int interval_counter;
//Value for sending ACC status to Raspberry Pi
volatile int pi_acc_state;
//For holding messages for the received mode
volatile int message_state;
//For maintaining the state of arduino
volatile int ino_state;

//For EEPROM address
//Sleep time recording address
const int ino_sleep_addr=0;
//Address for specifying sleep time
const int pi_sleep_wakeup_addr=1;
//Raspberry Pi shutdown wait time address
const int pi_shut_addr=2;

//Basically, the timer sleeps for 4 seconds x the specified number of times.
//4 seconds of the timer is done in the watchdog timer setting part
//4 seconds if the following is specified as 15.* 15 =60 seconds
const int count_max=15; 
//If the above is specified by 15, it can be specified every minute.
//For the following three items, the value recorded in EEPROM has priority.
//Specify the initial state (minutes) of sleep time below
volatile int wait_minutes=1; 
//Initial setting of shutdown waiting time (10 seconds unit) of Raspberry Pi
volatile int pi_shut_time=3;
//Specify the waiting time (in minutes) after starting Raspberry Pi
volatile int pi_osw_time=1;

//Variable for saving wait release time after starting Raspberry Pi
volatile long onslp_max_time; 
//Variable for saving time after starting Raspberry Pi
volatile long onslp_past_time;
// onslp_max_time overflow
volatile bool counter_switch=false;

//Status reset
void init_value()
{
  slp_interval_flg=false;
  message_state=0x00;
  slp_counter_flg=false;
}

//Pin set
void init_pins()
{
  pinMode(LED_PIN,OUTPUT);
  pinMode(PI_POWER,OUTPUT);
  pinMode(ACC_IN, INPUT);
}

//Check the ACC status at startup
void init_state()
{
  if (digitalRead(ACC_IN))
  {
    ino_state=0x00;
    slp_interval_flg=false;
  }else
  {
    ino_state=0x03;
    //ACC status change
    pi_acc_state=0x05;
  }
}

//Read config from 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;
  }
}

//Write config to EEPROM
//Specify address and value
void set_config(int addr, byte data)
{
  noInterrupts();
  EEPROM.write(addr,data);
  interrupts();
}

//Watchdog timer settings
void wdt_set()
{
  wdt_reset();
  cli();
  MCUSR = 0;
  //Set WDCE WDE
  WDTCSR |= 0b00011000;
  //WDIE settings Specify WDIF in 4 second increments
  WDTCSR =  0b01000000 | 0b100000;
  sei();
}

//Unset watchdog timer
void wdt_unset()
{
  wdt_reset();
  cli();
  MCUSR = 0;
  //WDCE WDE settings
  WDTCSR |= 0b00011000;
  //State initialization
  WDTCSR =  0b00000000;
  sei();
}

//Called on return by watchdog timer
//This is a watchdog timer
ISR(WDT_vect)
{
  //Check the sleep counter flag
  if(slp_counter_flg)
  {
    //Increase the interval counter
    interval_counter++;
    //Ends sleep if the interval counter reaches the specified number of times
    //Called every 4 seconds if specified every 4 seconds in the watchdog timer settings
    // count_max is 15 and wait_If minutes is 1, it ends if you stand for 1 minute
    if( interval_counter >= (count_max * wait_minutes) )
    {
      //End of sleep
      slp_counter_flg = false;
    }
  }
}


//Change the flag and activate it when there is an ACC interrupt
void wakeUp()
{
  slp_counter_flg = false;
}

//arduino sleep
void sleep()
{
  interval_counter = 0;
  //Watchdog timer set
  wdt_set();
  //Sleep mode settings
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
  //ACC interrupt settings
  //If there is an ACC interrupt, change the flag and force it to start
  attachInterrupt(0,wakeUp, RISING); 
  //Set of sleep counter flags
  slp_counter_flg=true;
  //Loop until the sleep counter flag is cleared
  //ISR with watchdog timer(WDT_vect)Is called, so until there is a change or interrupt
  while(slp_counter_flg)
  {
    noInterrupts();  //cli();
    sleep_enable();
    interrupts();    //sei();
    sleep_cpu();  //cpu sleep
    sleep_disable();
  }
  //Unset watchdog timer
  wdt_unset(); 
  //Canceling the ACC interrupt setting
  detachInterrupt(0); 
}



//Receive messages from Raspberry Pi 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];
  } 
}

//Send a message to Raspberry Pi
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;  
 }
}

//Wait timer function (standby in seconds)
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){}
  }
  //Counter overflow measures
  else 
  {
    while(millis() > now){}
    while(millis() < out_time){}
  }
}

//Raspberry Pi power ON function
void pi_wakeup()
{
  digitalWrite(PI_POWER,HIGH);
  digitalWrite(LED_PIN,HIGH);
}



//Check sleep time
void read_time_slp()
{
  onslp_max_time = ( millis()+ 60000 * pi_osw_time );
  onslp_past_time = millis();
  //If it overflows, the process will be changed, so set the switch flag.
  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);  
}

//setup
void setup()
{
  //Initialization
  init_value();
  //Pin initialization
  init_pins();
  //I2C start
  Wire.begin(SLAVE_ADDRESS);
  //Receive message
  Wire.onReceive(get_message); 
  //Send message
  Wire.onRequest(send_message); 
  //Reading config from EEPROM
  read_rom_config();
  //State initialization, sleep without ACC connection
  init_state();
  //Wait a little
  delay(1000);
}

//Main loop
void loop()
{
  //Check the status of ACC every time
  int acc = digitalRead(ACC_IN);
  switch(ino_state)
  {
    //initial state
    //Record the activation of Raspberry Pi and ACC status, transition to normal status
    case 0x00:
      pi_wakeup();
      pi_acc_state=0x01;
      ino_state++;
      break;
    //Normal condition
    case 0x01: 
      //ACC is off, sleep interval flag is not set
      if( (acc==0) && (!slp_interval_flg) )
      {
        //To shut down Raspberry Pi
        ino_state++;
      }
      //Sleep interval flag only
      // case 0x04:When ACC is off, the sleep interval flag is set.
      else if(slp_interval_flg)
      {
        //Check the switch flag on the counter
        if(counter_switch)
        {
          //Normal processing
          //Current time onslp_max_More than time or overflowed onslp_past_If it is less than or equal to time, the interval flag is cleared.
          if((millis() > onslp_max_time) || (millis() < onslp_past_time))
          {
            slp_interval_flg = false;
          }
        }
       //Post-overflow processing
       //Current time onslp_past_less than time and onslp_max_If it is time or more, the interval flag is canceled.
        else
        {
          if( (millis() < onslp_past_time) && (millis() > onslp_max_time) )
          {
            slp_interval_flg = false;
          }
        }
      }
      break;

    //Raspberry Pi Shutdown
    case 0x02: 
      ino_state++;
      //Change the value of the ACC state variable
      pi_acc_state=0x05; 
      //Wait for the shutdown command to be executed
      wait_time(pi_shut_time * 10);
      //Raspberry Pi power off
      digitalWrite(PI_POWER,LOW); 
      digitalWrite(LED_PIN,LOW); 
      //After turning off the relay, let the Raspberry Pi wait properly until the power becomes zero.
      wait_time(pi_shut_time * 10);
      break;

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

    //After waking up from sleep
    //Check sleep interval and check ACC status
    case 0x04:
      slp_interval_flg=true;
      //Read if ACC is off_time_slp();To make the Raspberry Pi wait for the specified time without shutting it down
      if(acc==0)
      {
        read_time_slp();
      }
      //If ACC is ON, return as usual
      else
      {
        slp_interval_flg=false;
      }
      //Initial arduino state
      ino_state=0x00;
      break;
  }
}

setting file

conf.json


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

circuit diagram

Recommended Posts

Power on / off Raspberry pi on Arduino
Power on / off your PC with raspberry pi
Control power on / off of USB port of Raspberry Pi
pigpio on Raspberry pi
Cython on Raspberry Pi
Introduced pyenv on Raspberry Pi
Use NeoPixel on Raspberry Pi
Install OpenCV4 on Raspberry Pi 3
Install TensorFlow 1.15.0 on Raspberry Pi
Testing uart communication on Raspberry Pi
raspberry pi 4 centos7 install on docker
Install ghoto2 on Raspberry Pi (memo)
OpenCV installation procedure on Raspberry Pi
Detect switch status on Raspberry Pi 3
Install OpenMedia Vault 5 on Raspberry Pi 4
L Chika on Raspberry Pi C #
Build wxPython on Ubuntu 20.04 on raspberry pi 4
"Honwaka Notification Lamp" on Raspberry Pi Part 2
Detect "brightness" using python on Raspberry Pi 3!
USB boot on Raspberry Pi 4 Model B
"Honwaka Notification Lamp" on Raspberry Pi Part 1
Enable UART + serial communication on Raspberry Pi
Adafruit Python BluefruitLE works on Raspberry Pi.
Accelerate Deep Learning on Raspberry Pi 4 CPU
Set swap space on Ubuntu on Raspberry Pi
Programming normally with Node-RED programming on Raspberry Pi 3
Use the Grove sensor on the Raspberry Pi
Install 64-bit OS (bate) on Raspberry Pi
Install docker-compose on 64-bit Raspberry Pi OS
Run servomotor on Raspberry Pi 3 using python
"Honwaka Notification Lamp" on Raspberry Pi Part 3
Power SG-90 servo motor with raspberry pi
Build OpenCV-Python environment on Raspberry Pi B +
Detect temperature using python on Raspberry Pi 3!
Mount Windows shared folder on Raspberry Pi
Matrix multiplication on Raspberry Pi GPU (Part 2)
How to install NumPy on Raspberry Pi
I installed OpenCV-Python on my Raspberry Pi
Working with GPS on Raspberry Pi 3 Python
Raspberry Pi backup
Why detectMultiScale () is slow on Raspberry Pi B +
Build a Django environment on Raspberry Pi (MySQL)
Try using a QR code on a Raspberry Pi
Detect magnet switches using python on Raspberry Pi 3!
Enjoy electronic work with GPIO on Raspberry Pi
MQTT RC car with Arduino and Raspberry Pi
Make DHT11 available on Raspberry Pi + python (memo)
Beginning cross-compilation for Raspberry Pi Zero on Ubuntu
Sound the buzzer using python on Raspberry Pi 3!
Serial communication between Raspberry pi --Arduino Uno (Python)
Play with your Ubuntu desktop on your Raspberry Pi 4
Display CPU temperature every 5 seconds on Raspberry Pi 4
Connect to MySQL with Python on Raspberry Pi
Build a Python development environment on Raspberry Pi
Build an Arch Linux environment on Raspberry Pi
Record temperature and humidity with systemd on Raspberry Pi
Build an OpenCV4 environment on Raspberry Pi using Poetry
Run LEDmatrix interactively with Raspberry Pi 3B + on Slackbot
What is Raspberry Pi?
GPGPU with Raspberry Pi
Try debugging Python on Raspberry Pi with Visual Studio.