2015년 8월 20일 목요일

[9th Week] Sending Alert Mail(or Text)

We can generate Alert Stream from sensor streams in Raspberry Pi. I'm going to make a visual effect for alerts. One of the methods is sending mail. I tried two methods for sending mail.
- Sending mail on python code running on Raspberry Pi.
- Sending mail on MATLAB code running on my labtop.

Second method should need receiving data from RPi. I'll use similar code with the one which I used in plotting sensor data.

There could be several codes for sending mail, and here're some example codes I used.

1) Sending mail on Python (Raspberry Pi)

import smtplib

def send(addr, s):
  server = smtplib.SMTP("smtp.gmail.com", 587)
  server.starttls()
  server.login(‘foo@gmail.com', ‘pwd')
  server.sendmail(‘
foo@gmail.com', addr, s)
  server.quit()

I put my Gmail account and password in server.login(). With this, we can easily send a mail.
**Also here's important point. We should change account setting for Rasperry Pi here (https://www.google.com/settings/security/lesssecureapps) when authentication probelm occurs unless we put correct account info and codes**

2) Sending mail on MATLAB

mail = 'foo@gmail.com';
password = 'pwd';
server = 'smtp.gmail.com';
setpref('Internet','E_mail',mail);
setpref('Internet','SMTP_Server',server);
setpref('Internet','SMTP_Username',mail);
setpref('Internet','SMTP_Password',password);

props = java.lang.System.getProperties;
props.setProperty('mail.smtp.auth','true');
props.setProperty('mail.smtp.socketFactory.class','javax.net.ssl.SSLSocketFactory');
props.setProperty('mail.smtp.socketFactory.port','465');

sendmail('addr','Alert!','Msg From MATLAB');

Both method can occur short delay for sending mail when the function works. You can also send text message using '10digits'@vtext.com (for verizon, there're similar things for others).

2015년 8월 17일 월요일

[8th Week] Generating streams from multiple Arduinos&Sensors on RPi

Last week, I tried some works generating streams with data from sensors on Arduino. I used DHT11 for temperature and humidity, and MPU-6050 for acceleration and gyro. Based on these work, I added more sensors on Raspberry Pi with 2 more Arduinos. Here's the structure.



There're four Arduinos(Arduino 0, 1, 2, 3). Arduino 0 has DHT-22 and dust sensor for temperature, humidity, dust concentration. Arduino 1 has MPU-6050 for acceleration, gyro, and temperature. Arduino 2 has mini sound sensor for sound pressure. Arduino 3 has Tarts Gateway for Tarts wireless sensors.

Therefore, Raspberry can handle 8 sensor data at once. Sampling rates for sensor data are different each other. Raspberry can generate streams with this, and do similar work I did last week (generating alerts) with these streams.

Further works I have to do are:
 - Stabilizing sensor data. Sensors using analog output are giving raw data with noises, so it is not quite accurate.

 - Finding stable connection method of tarts sensors. Tarts sensors are not detected well at its gateway in some condition, but I don't know what is the optimized condition.

2015년 8월 10일 월요일

[7th Week] Stream Applications for Sensor Data

Last week, I made a code that reads data from 2 Arduino synchronously, and send them to other device with bluetooth.
I modified the code that could read asynchronous data with making separate condition for each sensor. Next step could be making streams with sensor data. Python package PStreams would help this work. It was provided from my mentor.

Here's python code running on Raspberry Pi.

#Sample Code For Reading Data From Arduino, Sending via Bluetooth
#Get several string lines from sensors every 1 sampling
if __name__ == '__main__':
    if __package__ is None:
        import sys
        from os import path
        sys.path.append( path.dirname( path.dirname( path.abspath(__file__) ) ) )

import sys
import serial # From Arduino
from Stream import Stream # From PStreams
# asynch_element_func operates asynchronously
# on messages that appear in any of its input
# streams in the order in which they arrive.
from Asynch import asynch_element_func
from example_window_single_in_single_out_stateful import subtract_mean
from example_window_single_in_single_out_stateful import exceeds_k_sigma
from PrintingFunctions import print_stream, print_list_of_streams

# Two Arduinos connected to Raspberry Pi
# Arduino 0 has temperature and humidity
port0 = "/dev/ttyACM0" #DHT11(temperature,humidity)
# Arduini 1 has acceleration, gyro, and temperature
port1 = "/dev/ttyACM1" #MPU6050(acc(x,y,z),gyro(x,y,z),temperature)
portout = "/dev/ttyAMA0" #For Bluetooth Output

serialFromArduino0 = serial.Serial(port0, 115200)
serialFromArduino0.flushInput() #DHT11

serialFromArduino1 = serial.Serial(port1, 115200)
serialFromArduino1.flushInput() #MPU6050

serialToMATLAB = serial.Serial(portout, 9600)
serialToMATLAB.flushInput()
serialToMATLAB.flushOutput() #Bluetooth


def getSensorData0(temp1, temp2): #DHT11
    print('*DHT11*')
    input1 = serialFromArduino0.readline()
    input2 = serialFromArduino0.readline()
    r_tem = input1.split()
    r_hum = input2.split()

    if(input1.find('temperature') != -1 and input2.find('humidity') != -1
       and len(r_tem) == 2 and len(r_hum) == 2):

        tem = r_tem[1]
        hum = r_hum[1]
        return(tem, hum)

    else:
        return(temp1, temp2)

def getSensorData1(temp1, temp2, temp3, temp4, temp5, temp6, temp7): #MPU6050
    r_accel = serialFromArduino1.readline()
    r_temp = serialFromArduino1.readline()
    r_gyro = serialFromArduino1.readline()
    accel = r_accel.split()
    temp = r_temp.split()
    gyro = r_gyro.split()

    if(r_accel.find('accel') != -1 and r_temp.find('temperature') != -1 and r_gyro.find('gyro') != -1 and len(accel) == 5 and len(temp) == 4 and len(gyro) ==5 ):

        acc_x, acc_y, acc_z = accel[2:5]
        temp = temp[1]
        gyro_x, gyro_y, gyro_z = gyro[2:5]

        return(acc_x,acc_y,acc_z,temp,gyro_x,gyro_y,gyro_z)

    else:
        return(temp1,temp2,temp3,temp4,temp5,temp6,temp7)

    
def condition(state):
    """ Condition on temperature and humidity
    """
    temperature, humidity = state
    return ((temperature > 24 and humidity > 45) or
            (temperature > 25 and humidity > 40))


def update_state_and_output_condition(
        value, stream_number, state):
    """ Function that updates the state when a new
    value appears on the stream specified by
    stream_number. The function then returns the
    condition on the new state.

    """
    # update the state
    state[stream_number] = value
    return (condition(state), state)


def main():
    print('starting...')

    temperature_stream = Stream('temperature')
    humidity_stream = Stream('humidity')
    acc_x_stream = Stream('acceleration_x')
    acc_y_stream = Stream('acceleration_y')
    acc_z_stream = Stream('acceleration_z')

    normed_x_stream = subtract_mean(acc_x_stream, window_size=100)
    normed_y_stream = subtract_mean(acc_y_stream, window_size=100)
    normed_z_stream = subtract_mean(acc_z_stream, window_size=100)

    alerts_x = exceeds_k_sigma(acc_x_stream, window_size=100)
    alerts_y = exceeds_k_sigma(acc_y_stream, window_size=100)
    alerts_z = exceeds_k_sigma(acc_z_stream, window_size=100)

    discomfort_stream = asynch_element_func(
        f=update_state_and_output_condition,
        inputs = [temperature_stream,humidity_stream],
        num_outputs=1,
        state=[0,0])

    normed_x_stream.set_name('accln_x_mean_removed')
    normed_y_stream.set_name('accln_y_mean_removed')
    normed_z_stream.set_name('accln_z_mean_removed')

    alerts_x.set_name('Alert_x')
    alerts_y.set_name('Alert_y')
    alerts_z.set_name('Alert_z')
    
    discomfort_stream.set_name('discomfort_stream')

    print_list_of_streams([
        temperature_stream, humidity_stream,
        acc_x_stream, acc_y_stream, acc_z_stream,
        normed_x_stream, normed_y_stream, normed_z_stream,
        alerts_x, alerts_y, alerts_z,
discomfort_stream])

    d1, d2 = '0','0'
    m1, m2, m3, m4, m5, m6, m7 = '0','0','0','0','0','0','0'

    # The main loop. Reading sensors from two Arduinos.
    while True:
        if serialFromArduino0.inWaiting() > 0  or serialFromArduino1.inWaiting() > 0:
            if serialFromArduino1.inWaiting() > 0:
                if (serialFromArduino1.readline().find('*') != -1):
                    acc_x,acc_y,acc_z,temp,gyro_x,gyro_y,gyro_z = getSensorData1(m1, m2, m3, m4, m5, m6, m7)
                    m1, m2, m3, m4, m5, m6, m7 = acc_x, acc_y, acc_z, temp, gyro_x, gyro_y, gyro_z
                    print 'sensor data 1',acc_x,acc_y,acc_z,temp,gyro_x,gyro_y,gyro_z
                    acc_x_stream.append(int(acc_x))
                    acc_y_stream.append(int(acc_y))
                    acc_z_stream.append(int(acc_z))
                    if alerts_x.stop > 0:
                        alertx = alerts_x.recent[:alerts_x.stop][alerts_x.stop-1]
                        alerty = alerts_y.recent[:alerts_y.stop][alerts_y.stop-1]
                        alertz = alerts_z.recent[:alerts_z.stop][alerts_z.stop-1]
                        serialToMATLAB.write('*\n' + acc_x + '\n' + acc_y + '\n' + acc_z + '\n' + str(alertx) + '\n' + str(alerty) + '\n' + str(alertz) + '\n')
                    else:
                        serialToMATLAB.write('*\n' + acc_x + '\n' + acc_y + '\n' + acc_z + '\n' + '0' + '\n' + '0' + '\n' + '0' + '\n')

            if serialFromArduino0.inWaiting() > 0:
                if serialFromArduino0.readline().find('*') != -1:
                    tem, hum = getSensorData0(d1, d2)
                    d1, d2 = tem, hum
                    print 'sensor data 0', tem, hum
                    temperature_stream.append(float(tem))
                    humidity_stream.append(float(hum))
                    temperature_stream.print_recent()
                    humidity_stream.print_recent()

if __name__ == '__main__':
    main()

This can generate streams for temperature, humidity, and acceleration (x,y,z). Also, I added some additional lines for stable running. Some error occurs when the program can't read the data string from Arduino properly, so some exception is added for that.


Additionally, after generating streams for data, it could generate alerts for unusual conditions.
For example, uncomfortable conditions can be set for temperature and humidity, and alert comes when the current data violates this.
For acceleration, it can gather some data for a while, and calculate some statistical things. When the sigma of current data exceeds the threshold, it generates alerts.
Here's sample of printed data. Upper one is about DHT11, and the other is 2 sample of MPU6050.

Also, we can apply it with bluetooth connection. I captured the acceleration stream and alert stream with MATLAB.
Upper one is Acceleration (x,y,z) and below graphs are alerts. We can see the alert generated when I shake the sensor.