I have not been able to change existing sketches for cayenne yet.
I made an automatic fertilizer of hydroponic culture with Arduino.
I’d like to upload the value (loggingData ()
saved on the SD card in the sketch to cayenne. And I would like to be able to change the fertilizer concentration setting (ECvalu) from the Cayenne slider widget.
Thank you very much for your kind guidance.
Try changing sketch based on what you taught.
Here is the existing sketch.
#include <Wire.h>
#include "GravityRtc.h"
#include <BH1750.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>
#include <SPI.h>
#include <OneWire.h>
//EC設定値
//トマト参考値 育苗期1.2 定植初期1.2-1.5 中期(交配期)1.2-1.8 収穫期~後期2.0-2.8
//X500 dil. HyponicaはEC 1.4程度だった
//設定可能範囲はEC1.1mS/cm以上から
//ECvalu=X-0.05 Xに設定したいEC値を入力 0.05は補正値
float ECvalu=1.3-0.05;
//補水量閾値以下カウント数格納
int WLvCt=0;
//補水量(一回分)
int W_add_vol=250;
//水位測定繰り返し回数
int WLvVar=0;
// EC閾値以下カウント数格納
int EC_val=0;
//EC測定繰り返し回数
int ECvar=0;
//液肥追加量(一回分)
int F_add_vol=2;
//スイッチ設定
int P_pin = 7; // Primeスイッチ入力ピン番号
int P_state = 0; // Primeスイッチより取得したデータ格納用
int T_pin = 9; // Testスイッチ入力ピン番号
int T_state = 0; // Testスイッチより取得したデータ格納用
//EC設定
// # Connection:
// # EC meter output -> Analog pin 1
// # DS18B20 digital pin -> Digital pin 2
// #
#define StartConvert 0
#define ReadTemperature 1
const byte numReadings = 20; //the number of sample times
byte ECsensorPin = A1; //EC Meter analog output,pin on analog 1
byte DS18B20_Pin = 2; //DS18B20 signal, pin on digital 2
unsigned int AnalogSampleInterval=25,printInterval=700,tempSampleInterval=850; //analog sample interval;serial print interval;temperature sample interval
unsigned int readings[numReadings]; // the readings from the analog input
byte index = 0; // the index of the current reading
unsigned long AnalogValueTotal = 0; // the running total
unsigned int AnalogAverage = 0,averageVoltage=0; // the average
unsigned long AnalogSampleTime,printTime,tempSampleTime;
float temperature,ECcurrent;
//Temperature chip i/o
OneWire ds(DS18B20_Pin); // on digital pin 2
float TempProcess(bool ch)
{
//returns the temperature from one DS18B20 in DEG Celsius
static byte data[12];
static byte addr[8];
static float TemperatureSum;
if(!ch){
if ( !ds.search(addr)) {
Serial.println( F("no more sensors on chain, reset search!") );
ds.reset_search();
return 0;
}
if ( OneWire::crc8( addr, 7) != addr[7]) {
Serial.println( F("CRC is not valid!") );
return 0;
}
if ( addr[0] != 0x10 && addr[0] != 0x28) {
Serial.print( F("Device is not recognized!") );
return 0;
}
ds.reset();
ds.select(addr);
ds.write(0x44,1); // start conversion, with parasite power on at the end
}
else{
byte present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for (int i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
ds.reset_search();
byte MSB = data[1];
byte LSB = data[0];
float tempRead = ((MSB << 8) | LSB); //using two's compliment
TemperatureSum = tempRead / 16;
}
return TemperatureSum;
}
//水位測定設定
const int WLvPin=8;
int WLvVal = HIGH; //水位初期値
//SD設定
char timestamp[30];
const int chipSelect =4; //pin for chipselect SD card
// Create a file to store the data
File dataFile;
//モーター制御セットアップ
int WLv_motorPin = 10; // The pin connected to the transistor base
int WLv_Mvol=0; //モーターカウンター
//EC-A調整モーター
int EC_A_motorPin = 5; // The pin connected to the transistor base
int EC_A_Mvol=0; //モーターカウンター
//RTC設定
GravityRtc rtc; //RTC Initialization
//光センサーアドレス
BH1750 lightMeter(0x23);
int Lval=0; // lux値格納
//LCT設定
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x3F for a 20 chars and 4 line display
//Function
//EC測定
void EC_mesure() {
/*
Every once in a while,sample the analog value and calculate the average.
*/
if(millis()-AnalogSampleTime>=AnalogSampleInterval)
{
AnalogSampleTime=millis();
// subtract the last reading:
AnalogValueTotal = AnalogValueTotal - readings[index];
// read from the sensor:
readings[index] = analogRead(ECsensorPin);
// add the reading to the total:
AnalogValueTotal = AnalogValueTotal + readings[index];
// advance to the next position in the array:
index = index + 1;
// if we're at the end of the array...
if (index >= numReadings)
// ...wrap around to the beginning:
index = 0;
// calculate the average:
AnalogAverage = AnalogValueTotal / numReadings;
}
/*
Every once in a while,MCU read the temperature from the DS18B20 and then let the DS18B20 start the convert.
Attention:The interval between start the convert and read the temperature should be greater than 750 millisecond,or the temperature is not accurate!
*/
if(millis()-tempSampleTime>=tempSampleInterval)
{
tempSampleTime=millis();
temperature = TempProcess(ReadTemperature); // read the current temperature from the DS18B20
TempProcess(StartConvert); //after the reading,start the convert for next reading
}
/*
Every once in a while,print the information on the serial monitor.
*/
if(millis()-printTime>=printInterval)
{
printTime=millis();
averageVoltage=AnalogAverage*(float)5000/1024;
float TempCoefficient=1.0+0.0185*(temperature-25.0); //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.0185*(fTP-25.0));
float CoefficientVolatge=(float)averageVoltage/TempCoefficient;
if(CoefficientVolatge<150)Serial.println( F("No solution!") ); //25^C 1413us/cm<-->about 216mv if the voltage(compensate)<150,that is <1ms/cm,out of the range
else if(CoefficientVolatge>3300)Serial.println( F("Out of the range!") ); //>20ms/cm,out of the range
else
{
if(CoefficientVolatge<=448)ECcurrent=6.84*CoefficientVolatge-64.32; //1ms/cm<EC<=3ms/cm
else if(CoefficientVolatge<=1457)ECcurrent=6.98*CoefficientVolatge-127; //3ms/cm<EC<=10ms/cm
else ECcurrent=5.3*CoefficientVolatge+2278; //10ms/cm<EC<20ms/cm
ECcurrent/=1000; //convert us/cm to ms/cm
Serial.print(ECcurrent,2); //two decimal
Serial.println( F("ms/cm") );
}
}
if (ECcurrent < ECvalu){
EC_val++; //ECが指定値より低かった回数をカウント
}
else{
EC_val =0; //EC_valリセット
}
}
/*
ch=0,let the DS18B20 start the convert;ch=1,MCU read the current temperature from the DS18B20.
*/
//水位測定
void WLv_mesure() {
//read the switch value into a variable
WLvVal = digitalRead(WLvPin);
//print out the value of the liquid level
Serial.println(WLvVal);
if (WLvVal== LOW){
WLvCt++; //水位が指定値より低かった回数をカウント
}
else{
WLvCt =0; //WLvCtリセット
}
}
//LCDへ測定結果を表示
void LCD()
{
rtc.read();
lcd.clear();
lcd.print(rtc.year);
lcd.print( F("/") );
lcd.print(rtc.month);
lcd.print( F("/") );
lcd.print(rtc.day);
lcd.print(" ");
lcd.print(rtc.hour);
lcd.print( F(":") );
lcd.print(rtc.minute);
lcd.print( F(":") );
lcd.print(rtc.second);
lcd.setCursor(0,1);
lcd.print( F("EC: ") );
lcd.print(ECcurrent,2);
lcd.print( F("ms/cm") );
lcd.setCursor(0,2);
lcd.print( F("Temp: ") );
lcd.print(temperature);
lcd.print( F(" ^C ") );
lcd.setCursor(0,3);
lcd.print( F("Lux: ") );
lcd.print(Lval);
lcd.print(" ");
lcd.print( F("Low: ") );
lcd.print(WLvCt);
lcd.print(" ");
lcd.print( EC_val);
}
void Lux_mesure(){ //Lux測定テンプレート
uint16_t lux = lightMeter.readLightLevel();
Lval=lux*2;
}
// call back for file timestamps
void dateTime(uint16_t* date, uint16_t* time) {
rtc.read();
sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", rtc.hour,rtc.minute,rtc.second,rtc.month,rtc.day,rtc.year-2000);
Serial.println("yy");
Serial.println(timestamp);
// return date using FAT_DATE macro to format fields
*date = FAT_DATE(rtc.year, rtc.month, rtc.day);
// return time using FAT_TIME macro to format fields
*time = FAT_TIME(rtc.hour, rtc.minute, rtc.second);
}
//SD使用中警告
void SDalert()
{
lcd.clear();
lcd.print( F("The SD card is busy.") );
lcd.setCursor(0,1);
lcd.print( F("Do not turn off ") );
lcd.setCursor(0,2);
lcd.print( F("the power or ") );
lcd.setCursor(0,3);
lcd.print( F("remove the SD card.") );
}
//データ保存タイムスタンプ
void loggingTime() {
rtc.read();
SDalert();
dataFile=SD.open(( F("datalog.csv") ) , FILE_WRITE);
if (dataFile) {
dataFile.print(rtc.year);
dataFile.print( F("/") );
dataFile.print(rtc.month);
dataFile.print( F("/") );
dataFile.print(rtc.day);
dataFile.print(", ");
dataFile.print(rtc.hour);
dataFile.print( F(":") );
dataFile.print(rtc.minute);
dataFile.print( F(":") );
dataFile.print(rtc.second);
dataFile.print(", ");
}
dataFile.close();
delay(1000);
}
//データ保存
void loggingData() {
dataFile=SD.open(( F("datalog.csv") ) , FILE_WRITE);
if (dataFile) {
dataFile.print( F("Date Log: ") );
dataFile.print(", ");
dataFile.print( F("EC: ") );
dataFile.print(", ");
dataFile.print(ECcurrent,2);
dataFile.print(", ");
dataFile.print( F("ms/cm") );
dataFile.print(", ");
dataFile.print( F("temp:") );
dataFile.print(", ");
dataFile.print(temperature);
dataFile.print(", ");
dataFile.print( F("^C ") );
dataFile.print(", ");
dataFile.print( F("Light: ") );
dataFile.print(", ");
dataFile.print(Lval);
dataFile.print(", ");
dataFile.print( F("lx") );
dataFile.print(", ");
dataFile.print( F("Water level: ") );
dataFile.print(", ");
dataFile.print(WLvVal);
dataFile.println(",");
}
dataFile.close();
delay(3000);
LCD();
}
//水位 EC調整
void Adjust_WLv_EC()
{
for (WLvVar=0; WLvVar <= 10; WLvVar++){
WLv_mesure();
delay(3000);
}
while
(WLvVal == LOW && WLv_Mvol < 4 && WLvCt > 5 ){ //指定水位以下で、添加数4回以下 のときかつ5回水位が閾値を下回ったとき
digitalWrite(WLv_motorPin,LOW);
delay(W_add_vol*844UL); //1mL添加に844msec
digitalWrite(WLv_motorPin,HIGH);
WLv_Mvol++; //モーターを回したら、添加数+1
delay(3000); //3秒安定化させる
//WLv 次回ループのための測定(10回)
for (WLvVar=0; WLvVar <= 10; WLvVar++){
WLv_mesure();
delay(3000);
}
}
//補水量SD保存
if (WLv_Mvol!=0){
loggingTime();
dataFile=SD.open(( F("datalog.csv") ) , FILE_WRITE);
if (dataFile) {
dataFile.print( F("Action Log: ") );
dataFile.print(", ");
dataFile.print( F("Add") );
dataFile.print(", ");
dataFile.print(WLv_Mvol*W_add_vol);
dataFile.print(", ");
dataFile.print( F("mL of water, ") );
dataFile.println(",");
}
dataFile.close();
delay(3000);
LCD();
WLv_Mvol =0; //モータカウントリセット
delay(3000);
}
for (ECvar=0; ECvar <= 10; ECvar++){
EC_mesure();
delay(3000);
}
while
(ECcurrent < ECvalu && EC_A_Mvol < 5 && EC_val > 5 ){ //EC指定値以下の時(333倍希釈ハイポニカのEC値が1.2)で、添加数5回以下かつ5回ECが閾値を下回ったとき
digitalWrite(EC_A_motorPin ,LOW);
delay(F_add_vol*4191UL); //1mL添加に4191msec
digitalWrite(EC_A_motorPin,HIGH);
EC_A_Mvol++; //モーターを回したら、添加数+1
delay(900000UL); //15分安定化させる
//WLv 次回ループのための測定(10回)
for (ECvar=0; ECvar <= 10; ECvar++){
EC_mesure();
delay(3000);
}
}
//Hyponica添加量SD保存
if ( EC_A_Mvol!=0){
loggingTime();
dataFile=SD.open(( F("datalog.csv") ) , FILE_WRITE);
if (dataFile) {
dataFile.print( F("Action Log: ") );
dataFile.print(", ");
dataFile.print( F("Add") );
dataFile.print(", ");
dataFile.print(EC_A_Mvol*F_add_vol);
dataFile.print(", ");
dataFile.print( F("mL of x500 Hyponica, ") );
dataFile.println(",");
}
dataFile.close();
delay(3000);
LCD();
EC_A_Mvol =0; //モータカウントリセット
delay(300);
}
}
void setup() {
//LCDセットアップ
// initialize the LCD
lcd.begin();
lcd.backlight();
//モーターピン初期値
pinMode(WLv_motorPin, OUTPUT);
digitalWrite(WLv_motorPin, HIGH);
pinMode(EC_A_motorPin, OUTPUT);
digitalWrite(EC_A_motorPin, HIGH);
//スイッチセットアップ
pinMode(P_pin, INPUT); // ボタンスイッチ用に入力に設定
pinMode(T_pin, INPUT); // ボタンスイッチ用に入力に設定
//ECセットアップ
// initialize serial communication with computer:
Serial.begin(115200);
// initialize all the readings to 0:
for (byte thisReading = 0; thisReading < numReadings; thisReading++)
readings[thisReading] = 0;
TempProcess(StartConvert); //let the DS18B20 start the convert
AnalogSampleTime=millis();
printTime=millis();
tempSampleTime=millis();
//水位測定 セットアップ
pinMode(WLvPin, INPUT);
//RCTセットアップ
rtc.setup();
//rtc.adjustRtcが有効になっていると、Arduino再起動時に時間がコンパイル時に戻ってしまうためコメントアウト
//Set the RTC time automatically: Calibrate RTC time by your computer time
//rtc.adjustRtc(F(__DATE__), F(__TIME__));
//Set the RTC time manually
//rtc.adjustRtc(2017,6,19,1,12,7,0); //Set time: 2017/6/19, Monday, 12:07:00
//光センサーセットアップ
// Initialize the I2C bus (BH1750 library doesn't do this automatically)
Wire.begin();
lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE);
//センサテスト
T_state = digitalRead(T_pin); // ピンよりデータ取得
while(T_state==1)
{
WLv_mesure();
EC_mesure();
Lux_mesure();
LCD();
delay(3000);
T_state = digitalRead(T_pin);
}
// set date time callback function(SD time stamp)
SdFile::dateTimeCallback(dateTime);
rtc.read();
sprintf(timestamp, "%02d:%02d:%02d %2d/%2d/%2d \n", rtc.hour,rtc.minute,rtc.second,rtc.month,rtc.day,rtc.year-2000);
Serial.println("xx");
Serial.println(timestamp);
//SD セットアップ
SDalert();
// setup for the SD card
Serial.print( F("Initializing SD card...") );
while(!SD.begin(chipSelect)) {
Serial.println( F("initialization failed!") );
lcd.clear();
lcd.print( F("SD initialization") );
lcd.setCursor(0,1);
lcd.print( F("failed! ") );
lcd.setCursor(0,2);
lcd.print( F("Please check the SD") );
lcd.setCursor(0,3);
lcd.print( F("and reboot the syst.") );
delay(5000);
}
Serial.println( F("initialization done.") );
//reboot log
loggingTime();
dataFile=SD.open(( F("datalog.csv") ) , FILE_WRITE);
if (dataFile) {
dataFile.print( F("Reboot Log: ") );
dataFile.print(", ");
dataFile.print( F("File opened ok") );
dataFile.println(",");
lcd.clear();
lcd.print( F("SD File opened ok") );
}
dataFile.close();
delay(5000);
//ポンププライミング
P_state = digitalRead(P_pin); // ピンよりデータ取得
if(P_state==1)
{
digitalWrite(WLv_motorPin, LOW);
delay(60000UL);
digitalWrite(WLv_motorPin,HIGH);
digitalWrite(EC_A_motorPin , LOW);
delay(10000UL);
digitalWrite(EC_A_motorPin,HIGH);
delay(60000UL);
}
}
// put your setup code here, to run once:
void loop() {
//測定
WLv_mesure();
EC_mesure();
Lux_mesure();
LCD();
//記録
loggingTime();
loggingData();
//補正
Adjust_WLv_EC();
//測定
WLv_mesure();
EC_mesure();
Lux_mesure();
LCD();
//記録
loggingTime();
loggingData();
delay(900000UL);//15分間隔
}