개발자/라즈베리파이4

라즈베리파이4 데이터베이스 브라우저 연동 테스트 에러 해결

지구빵집 2022. 5. 22. 17:29
반응형

 

 

 

센서값을 저장하는 서버 프로그램이 있어야 한다. 프로그램은 demodb.cpp 파일로 만든다. 아래는 전체 코드를 보여준다. 소스코드는 길지만 윗부분의 데이터베이스 설정하고 연결하는 부분만 참고한다. 라인넘버는 53, 108 라인 부근이다. 

 

142 라인의 delay 값을 바꾸면 반복적으로 데이터베이스에 센서 데이터를 저장하는 시간을 변경할 수 있다.

 

#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <wiringPi.h>
#include <wiringPiSPI.h>

#include <mysql/mysql.h>

#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>

#include <time.h>
#include <math.h>

#define CS_MCP3208  8        // BCM_GPIO_8

#define SPI_CHANNEL 0
#define SPI_SPEED   1000000   // 1MHz

#define VCC         4.8       // Supply Voltage

// define farm 
#define MAXTIMINGS 85
#define RETRY 5

#define PUMP	21 // BCM_GPIO 5
#define FAN	22 // BCM_GPIO 6
#define DCMOTOR 23 // BCM_GPIO 13
#define RGBLEDPOWER  24 //BCM_GPIO 19
#define RED	7
#define GREEN	8
#define BLUE	9
#define LIGHTSEN_OUT 2  //gpio27 - J13 connect

int ret_humid, ret_temp;

static int DHTPIN = 11;
static int dht22_dat[5] = {0,0,0,0,0};

int read_dht22_dat_temp();
int read_dht22_dat_humid();
int get_temperature_sensor();
int get_humidity_sensor();
int get_light_sensor();

static int read_dht22_dat();

// here

//#define DBHOST "localhost"
#define DBHOST "127.0.0.1"
#define DBUSER "smartiot"
#define DBPASS "1234"
#define DBNAME "demofarmdb"

MYSQL *connector;
MYSQL_RES *result;
MYSQL_ROW row;

int read_mcp3208_adc(unsigned char adcChannel)
{
  unsigned char buff[3];
  int adcValue = 0;

  buff[0] = 0x06 | ((adcChannel & 0x07) >> 2);
  buff[1] = ((adcChannel & 0x07) << 6);
  buff[2] = 0x00;

  digitalWrite(CS_MCP3208, 0);  // Low : CS Active

  wiringPiSPIDataRW(SPI_CHANNEL, buff, 3);

  buff[1] = 0x0F & buff[1];
  adcValue = ( buff[1] << 8) | buff[2];

  digitalWrite(CS_MCP3208, 1);  // High : CS Inactive

  return adcValue;
}


int main (void)
{
  int adcChannel  = 0;
  int adcValue[8] = {0};

  if (wiringPiSetup() == -1)
    exit(EXIT_FAILURE) ;
	
  if (setuid(getuid()) < 0)
  {
    perror("Dropping privileges failed\n");
    exit(EXIT_FAILURE);
  }

  if(wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1)
  {
    fprintf (stdout, "wiringPiSPISetup Failed: %s\n", strerror(errno));
    return 1 ;
  }
  
  pinMode(CS_MCP3208, OUTPUT);

  // MySQL connection
  connector = mysql_init(NULL);
  if (!mysql_real_connect(connector, DBHOST, DBUSER, DBPASS, DBNAME, 3306, NULL, 0))
  {
    fprintf(stderr, "%s\n", mysql_error(connector));
    return 0;
  }

  printf("MySQL(rpidb) opened.\n");
  
  while(1)
  {
    char query[1024];

    adcValue[0] = get_temperature_sensor(); // Temperature Sensor
    
    adcValue[1] = get_humidity_sensor(); // Humidity Sensor
    
    adcValue[2] = get_light_sensor(); // Illuminance Sensor
	
    adcValue[3] = read_mcp3208_adc(3); // Mic Sensor
    adcValue[4] = read_mcp3208_adc(4); // Flame Sensor
    adcValue[5] = read_mcp3208_adc(5); // Acceleration Sensor (Z-Axis)
    adcValue[6] = read_mcp3208_adc(6); // Gas Sensor
    adcValue[7] = read_mcp3208_adc(7); // Distace Sensor
    //adcValue[7] = 27*pow((double)(adcValue[7]*VCC/4095), -1.10);

    sprintf(query,"insert into thl values (now(),%d,%d,%d)", adcValue[0],adcValue[1],adcValue[2]);

    if(mysql_query(connector, query))
    {
      fprintf(stderr, "%s\n", mysql_error(connector));
      printf("Write DB error\n");
    }

    delay(3000); //1sec delay
  }

  mysql_close(connector);

  return 0;
}

int get_temperature_sensor()
{
	int received_temp;
	int _retry = RETRY;

	//DHTPIN = 11;

	/*if (wiringPiSetup() == -1)
		exit(EXIT_FAILURE) ;*/
	
	if (setuid(getuid()) < 0)
	{
		perror("Dropping privileges failed\n");
		exit(EXIT_FAILURE);
	}
	while (read_dht22_dat_temp() == 0 && _retry--)
	{
		delay(500); // wait 1sec to refresh
	}
	received_temp = ret_temp ;
	printf("Temperature = %d\n", received_temp);
	
	return received_temp;
}

static uint8_t sizecvt(const int read)
{
  /* digitalRead() and friends from wiringpi are defined as returning a value
  < 256. However, they are returned as int() types. This is a safety function */

  if (read > 255 || read < 0)
  {
    printf("Invalid data from wiringPi library\n");
    exit(EXIT_FAILURE);
  }
  return (uint8_t)read;
}

int read_dht22_dat_temp()
{
  uint8_t laststate = HIGH;
  uint8_t counter = 0;
  uint8_t j = 0, i;

  dht22_dat[0] = dht22_dat[1] = dht22_dat[2] = dht22_dat[3] = dht22_dat[4] = 0;

  // pull pin down for 18 milliseconds
  pinMode(DHTPIN, OUTPUT);
  digitalWrite(DHTPIN, HIGH);
  delay(10);
  digitalWrite(DHTPIN, LOW);
  delay(18);
  // then pull it up for 40 microseconds
  digitalWrite(DHTPIN, HIGH);
  delayMicroseconds(40); 
  // prepar
  
  pinMode(DHTPIN, INPUT);

  // detect change and read data
  for ( i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while (sizecvt(digitalRead(DHTPIN)) == laststate) {
      counter++;
      delayMicroseconds(1);
      if (counter == 255) {
        break;
      }
    }
    laststate = sizecvt(digitalRead(DHTPIN));

    if (counter == 255) break;

    // ignore first 3 transitions
    if ((i >= 4) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      dht22_dat[j/8] <<= 1;
      if (counter > 16)
        dht22_dat[j/8] |= 1;
      j++;
    }
  }

  // check we read 40 bits (8bit x 5 ) + verify checksum in the last byte
  // print it out if data is good
  if ((j >= 40) && 
      (dht22_dat[4] == ((dht22_dat[0] + dht22_dat[1] + dht22_dat[2] + dht22_dat[3]) & 0xFF)) ) {
        float t, h;
		
        h = (float)dht22_dat[0] * 256 + (float)dht22_dat[1];
        h /= 10;
        t = (float)(dht22_dat[2] & 0x7F)* 256 + (float)dht22_dat[3];
        t /= 10.0;
        if ((dht22_dat[2] & 0x80) != 0)  t *= -1;
		
		ret_humid = (int)h;
		ret_temp = (int)t;
		printf("Humidity = %.2f %% Temperature = %.2f *C \n", h, t );
		printf("Humidity = %d Temperature = %d\n", ret_humid, ret_temp);
		
    return ret_temp;
  }
  else
  {
    printf("Data not good, skip\n");
    return 0;
  }
}


int get_humidity_sensor()
{
	int received_humid;
	int _retry = RETRY;

	//DHTPIN = 11;

	/*if (wiringPiSetup() == -1)
		exit(EXIT_FAILURE) ;*/
	
	if (setuid(getuid()) < 0)
	{
		perror("Dropping privileges failed\n");
		exit(EXIT_FAILURE);
	}

	while (read_dht22_dat_humid() == 0 && _retry--) 
	{
		delay(500); // wait 1sec to refresh
	}

	received_humid = ret_humid;
	printf("Humidity = %d\n", received_humid);
	
	return received_humid;
}

int read_dht22_dat_humid()
{
	uint8_t laststate = HIGH;
	uint8_t counter = 0;
	uint8_t j = 0, i;

	dht22_dat[0] = dht22_dat[1] = dht22_dat[2] = dht22_dat[3] = dht22_dat[4] = 0;

	// pull pin down for 18 milliseconds
	pinMode(DHTPIN, OUTPUT);
	digitalWrite(DHTPIN, HIGH);
	delay(10);
	digitalWrite(DHTPIN, LOW);
	delay(18);
	// then pull it up for 40 microseconds
	digitalWrite(DHTPIN, HIGH);
	delayMicroseconds(40); 
	// prepare to read the pin
	pinMode(DHTPIN, INPUT);

	// detect change and read data
	for ( i=0; i< MAXTIMINGS; i++) 
	{
		counter = 0;
		while (sizecvt(digitalRead(DHTPIN)) == laststate) 
		{
			counter++;
			delayMicroseconds(1);
			if (counter == 255) {
			break;
		    }
        }
        laststate = sizecvt(digitalRead(DHTPIN));

        if (counter == 255) break;

        // ignore first 3 transitions
        if ((i >= 4) && (i%2 == 0)) 
        {
            // shove each bit into the storage bytes
            dht22_dat[j/8] <<= 1;
            if (counter > 16)
                dht22_dat[j/8] |= 1;
            j++;
        }
    }

  // check we read 40 bits (8bit x 5 ) + verify checksum in the last byte
  // print it out if data is good
	if ((j >= 40) && 
      (dht22_dat[4] == ((dht22_dat[0] + dht22_dat[1] + dht22_dat[2] + dht22_dat[3]) & 0xFF)) ) {
        float t, h;
		
        h = (float)dht22_dat[0] * 256 + (float)dht22_dat[1];
        h /= 10;
        t = (float)(dht22_dat[2] & 0x7F)* 256 + (float)dht22_dat[3];
        t /= 10.0;
        if ((dht22_dat[2] & 0x80) != 0)  t *= -1;
		
		ret_humid = (int)h;
		ret_temp = (int)t;
		printf("Humidity = %.2f %% Temperature = %.2f *C \n", h, t );
		printf("Humidity = %d Temperature = %d\n", ret_humid, ret_temp);
		
    return ret_humid;
	}
	else
	{
		printf("Data not good, skip\n");
		return 0;
	}
}

int wiringPicheck(void)
{
	if (wiringPiSetup () == -1)
	{
		fprintf(stdout, "Unable to start wiringPi: %s\n", strerror(errno));
		return 1 ;
	}
}

int get_light_sensor(void)
{
	// sets up the wiringPi library
	/*if (wiringPiSetup () < 0) 
	{
		fprintf (stderr, "Unable to setup wiringPi: %s\n", strerror (errno));
		return 1;
	}*/
	
	if(digitalRead(LIGHTSEN_OUT))	//day
		return 1;
	else //night
		return 0;

}

 

위 코드를 아래와 같은 명령어를 사용해 컴파일 한다.

 

$ g++ -o demodb demodb.cpp -lwiringPi -mariadbclient  

 

실행은 

 

$ sudo ./demodb  

 

실행하면 3초 간격으로 센서 데이터 값을 읽어 데이터베이스 demofarmdb의 적당한 테이블에 기록한다. 아래는 실행 화면이다.

 

pi@raspberrypi:~/demofarmdb $ sudo ./demodb
MySQL(rpidb) opened.
Humidity = 52.20 % Temperature = 27.10 *C
Humidity = 52 Temperature = 27
Temperature = 27
Humidity = 52.20 % Temperature = 27.10 *C
Humidity = 52 Temperature = 27
Humidity = 52
Humidity = 51.90 % Temperature = 27.10 *C
Humidity = 51 Temperature = 27
Temperature = 27
Humidity = 52.00 % Temperature = 27.10 *C
Humidity = 52 Temperature = 27
Humidity = 52
Humidity = 52.10 % Temperature = 27.10 *C
Humidity = 52 Temperature = 27
Temperature = 27
Humidity = 52.10 % Temperature = 27.10 *C
Humidity = 52 Temperature = 27
Humidity = 52

 

아래 php 파일을 실행시키느라 고생을 했는데 이전 버전에서는 아래와 같은 에러가 많이 발생했는데 다 수정하고 고쳤다.

 

 

Fatal error: Uncaught Error: Call to undefined function mysql_connect() in /var/www/html/viewfarm.php:4 Stack trace: #0 {main} thrown in /var/www/html/viewfarm.php on line 4

 

이 에러 해결 방법은 - mysql_connect() 함수는 php7이상부터 삭제됨(phpinfo()로 확인) mysqli_connect() 함수 써야함 구식 mysql 함수는 못 씀 pdo_mysql 이나 mysqli 둘 중에 하나 써야함  

 

Fatal error: Uncaught Error: Call to undefined function mysql_select_db() in /var/www/html/viewfarm.php:5 Stack trace: #0 {main} thrown in /var/www/html/viewfarm.php on line 5

 

위 에러는 아래 그림처럼 함수가 변경되었다. 그러니까 database 연결할 때 mysql_connect 가 아니라 mysqli_connect 를 사용해야 한다.

 

mysqli_connect

 

 

Fatal error: Uncaught Error: Call to undefined function mysql_query() in /var/www/html/viewfarm.php:8 Stack trace: #0 {main} thrown in /var/www/html/viewfarm.php on line 8

 

Connect Success!

Warning: mysqli_query() expects at least 2 parameters, 1 given in /var/www/html/viewfarm.php on line 8

Warning: mysqli_error() expects exactly 1 parameter, 0 given in /var/www/html/viewfarm.php on line 8 Query Fail:

 

 

이 에러는 mysql_query($query); -> mysqli_query($conn, $query); 를 사용해서 해결한다.

 

 

Connect Success!

Fatal error: Uncaught Error: Call to undefined function mysql_fetch_array() in /var/www/html/viewfarm.php:10 Stack trace: #0 {main} thrown in /var/www/html/viewfarm.php on line 10

Time TEM HUM ILL

 

 

이 에러는 

Fatal error: Uncaught Error: Call to undefined function mysql_fetch_array() 에러시

 

//mysql

while($row= mysql_fetch_array($result1)) { }

//mysqli

while($row= mysqli_fetch_object($result1)) { } // 이렇게 수정

 

Fatal error: Uncaught Error: Call to undefined function mysql_num_rows()

 

//mysql

$aaaa = mysql_num_rows($result_common);

//mysqli

$aaaa = mysqli_num_rows($result_common); // 이렇게 수정

 

 

Connect Success!

Warning: Use of undefined constant MYSQL_ASSOC - assumed 'MYSQL_ASSOC' (this will throw an Error in a future version of PHP) in /var/www/html/viewfarm.php on line 10

Warning: mysqli_fetch_array() expects parameter 2 to be int, string given in /var/www/html/viewfarm.php on line 10

 

Time TEM HUM ILL 

 

마지막 에러는 MYSQL_ASSOC --> MYSQLI_ASSOC 로 적어서 해결한다.

 

 

다음으로 웹에서 데이터베이스를 읽어 뿌려주는 php 파일을 viewfarm.php 파일로 만들어 준다. 코드가 잘 정리되지 않았지만 라즈베리파이 변경 구문을 모두 적용하여 잘 돌아간다.

 

<script language='javascript'>
  window.setTimeout('window.location.reload()',1000); </script>
<?php
$connect = mysqli_connect('localhost', 'smartiot', '1234', 'demofarmdb')
   or die("Connect Fail: " . mysql_error()); echo "Connect Success!";
   //mysql_select_db("demofarmdb") or die("Select DB Fail!");
   $query = "select
* from thl order by time desc limit 10"; $result = mysqli_query($connect, $query) or die("Query Fail: " . mysqli_error()); echo "<table>\n"; echo
"<tr><td>Time</td><td>TEM</td><td>HUM</td><td>ILL</td></tr>";
while ($line = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
   echo "\t<tr>\n";
   foreach ($line as $col_value) {
       echo "\t\t<td>$col_value</td>\n";
   }
   echo "\t</tr>\n";
}
echo "</table>\n"; mysqli_free_result($result); mysqli_close($connect);
?>

 

브라우저에서 데이터를 불러와 뿌려주는 아름다운 화면을 보게 된다. 축하한다. ^^

 

브라우저에서 데이터를 불러와 뿌려주는 아름다운 화면

 

 

 

 

반응형