目次
前
次
ZigBeeネットワーク構築
ビニルハウス、選果場、休息用家屋は、それなりに
離れているので、センサーネットワークを構築して
温度をリモート監視することが、本システムの要件
にありました。
センサーネットワークとして、次の3種を比較検討。
これらのネットワークを構築に必要なモジュールで
手持ちの調べてみます。
Wifi
Wi−FiモジュールESP−WROOM−02
(¥650)
Bluetooth
マイクロチップBluetoothモジュールRN42−I/RM
(¥1、650)
ZigBee
XBee ZB S2Cモジュール ワイヤーアンテナタイプ
(¥2、500)
<長距離の通信では、ワイヤーアンテナタイプが必須>
Wifiは、通信が途切れることがあり選択肢から外します。
Bluetoothは、室内通信が主体なので、こちらも選択肢
より除外。
屋外での通信が可能となると、ZigBeeしか残らないことに。
ZigBeeの電波到達距離は60m程度なので、Personal Computer
がある休息家屋とビニルハウスの端までは、充分カバー可能。
ネットワークトポロジーは、次のようにスター型に近くなります。
ZigBeeのネットワークには、coordinator、router、end deviceの
3種のノードが存在します。
coordinatorは、ネットワークのリーダとして機能し
routerは、coordinatorと通信する他に、通信不能な
ノード(router、end device)の情報交換の中継役を担当
します。
今回のZigBeeネットワークは、coordinatorにPersonal Computerを
接続して使います。
ZigBeeネットワークのノードであるXBeeには、シリアル
インタフェースと無線が具備されているので、遠隔にある
router、end deviceとの通信は、無線を利用。
router、end deviceには、Arduinoを接続して
XBeeを無線/シリアル変換器として使います。
システムイメージは、以下。
Arduinoスケッチには、シリアルで情報を取得する
コマンドが用意されています。
TeraTermでの操作では、次のようにデータを返して
きます。
Personal Computerのアプリケーションは、2分周期で
ビニルハウス内にある温度測定装置からデータを取得
して、ファイルに保存するとともにグラフを描画する
機能を持てばよいとします。
ビニルハウス内の温度計測装置では、ArduinoにXBeeを
接続するとともに、電源を強化しておきます。
XBeeは、送信と受信で50mAほどの電流を必要とするので
2次電池では、1日いっぱいの計測ができません。
電源は、5000mAhの容量をもつ、モバイルバッテリーを利用。
モバイルバッテリーは負荷が軽いとき、自動でパワーオフ
してしまうので、2秒周期で1秒間だけ電流を5mAだけ流す
アダプタを入れます。
ワンチップマイコンPIC12F1501を利用しました。
ArduinoとXBeeを1枚の基板に実装すると、以下。
モバイルバッテリーと並べても、A4用紙の面積に
収まります。
ZigBeeのネットワークを構築する前に
トランスペアラントモードで2台1組
による通信ができることを確認します。
トポロジーは、以下。
時間ごとのデータ取得と保存は、Personal Computerの
アプリケーションが担うとして、Arduinoのスケッチは
次のようにしました。
/*
thermog.ino
Pin assignment
PORTB
PB5 (output) LED
PB4 (output) --
PB3 (output) --
PB2 (output) --
PB1 (output) --
PB0 (output) --
PORTC
PC5 (output)
PC4 (output)
PC3 (output) light sensor
PC2 (output) sensor 2(TOP)
PC1 (output) sensor 1(MIDDLE)
PC0 (output) sensor 0(BOTTOM)
PORTD
PD7 (output) D7
PD6 (output) D6
PD5 (output) D5
PD4 (output) D4
PD3 (output) E
PD2 (output) RS
PD1 (output) TxD
PD0 (input) RxD
*/
#include <MsTimer2.h>
#include <LiquidCrystal.h>
#define OFF 0
#define ON OFF+1
/* pin assignment */
#define BOTTOM 0
#define MIDDLE 1
#define TOP 2
#define LAST 3
#define LED_BIT 5
#define XINTERVAL 1500
#define XLIMIT 35
#define YLIMIT 170
#define RSIZE 8
#define BSIZE 256
/* LCD rs , e , D4 , D5 , D6 , D7 */
LiquidCrystal lcd( 2, 3, 4, 5, 6, 7 );
/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
byte getHex(char x);
void rs_print(int x);
void makeLCDString();
void oneShot();
void ledProc(byte x);
void put_light_dark();
byte convBCD2HEX(byte x);
byte convHEX2BCD(byte x);
/* variables */
boolean tflag ;
boolean uflag ;
boolean oflag ;
boolean dflag ; /* day or night */
char sbuf[8] ;
byte sindex ;
byte cmd ;
int adv ;
int tv ;
int temp[4] ;
byte tempbcd[3] ;
char lineU[17];
char lineL[17];
void setup()
{
/* initialize serial */
Serial.begin(9600);
sindex = 0 ;
rs_puts("Hello !");
crlf();
/* clear flags */
tflag = OFF ;
uflag = OFF ;
oflag = ON ;
dflag = OFF ;
/* initialize port values */
PORTB = 0x00 ;
PORTC = 0x00 ;
PORTD = 0x00 ;
/* initialize port direction */
DDRB = 0xff ;
DDRC = 0x00 ;
DDRD = 0xfe ;
/* 1500ms period */
MsTimer2::set(XINTERVAL,update_trigger);
/* enable */
MsTimer2::start();
/* initialize LCD */
lcd.begin( 16, 2 );
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Measure");
lcd.setCursor(0, 1);
lcd.print("Hello, world!");
/* LCD string default */
for ( byte ii = 0 ; ii < 16 ; ii++ ) {
*(lineL+ii) = ' ' ;
*(lineU+ii) = ' ' ;
}
*(lineL+16) = '\0';
*(lineU+ 0) = 'T';
*(lineU+ 4) = '|';
*(lineU+ 5) = 'M';
*(lineU+ 9) = '|';
*(lineU+10) = 'B';
*(lineU+14) = '|';
*(lineU+15) = 'N';
*(lineU+16) = '\0';
}
void loop()
{
/* one time handling */
if ( oflag == ON ) {
/* clear flag */
oflag = OFF ;
/* default */
lcd.setCursor(0,1);
lcd.print("Namara Firm ");
}
/* command interpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* one shot */
if ( cmd == 'T' ) { oneShot(); }
/* turn on LED */
if ( cmd == 'L' ) { ledProc(1); }
/* turn off LED */
if ( cmd == 'l' ) { ledProc(0); }
/* new line */
crlf() ;
}
/* timer handling */
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* light or dark */
put_light_dark();
/* get thermometer */
for ( int ii = TOP ; ii > -1 ; ii-- ) {
/* get data */
adv = analogRead(ii);
/* convert (voltage) */
tv = map(adv,0,1023,0,5000);
/* convert (temparature) */
*(temp+ii) = map(tv,300,1600,-30,100);
/* show ( LCD ) */
makeLCDString();
lcd.setCursor(0,0); lcd.print( lineU );
lcd.setCursor(0,1); lcd.print( lineL );
}
}
}
void update_trigger()
{
/* set flag */
tflag = ON ;
}
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("T one shot") ; crlf();
rs_puts("L turn on LED") ; crlf();
rs_puts("l turn off LED"); crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
byte getHex(char x)
{
byte result ;
/* default */
result = 0 ;
/* judge */
if ( '0' <= x && x <= '9' ) { result = x - '0' ; }
if ( 'A' <= x && x <= 'F' ) { result = x - 'A' + 10 ; }
if ( 'a' <= x && x <= 'f' ) { result = x - 'a' + 10 ; }
return result ;
}
void rs_print(int x)
{
char msg[5] ;
int tmp ;
/* default */
*(msg+4) = '\0' ;
/* sign */
*(msg+0) = ' ' ;
tmp = x ;
if ( x < 0 ) {
tmp *= (-1) ;
*(msg+0) = '-' ;
}
/* generate code */
*(msg+3) = tmp % 10 + '0' ; tmp /= 10 ;
*(msg+2) = tmp % 10 + '0' ; tmp /= 10 ;
*(msg+1) = tmp % 10 + '0' ;
/* zero surpress */
if ( *(msg+1) == '0' ) {
*(msg+1) = ' ' ;
if ( *(msg+2) == '0' ) { *(msg+2) = ' ' ; }
}
/* show */
rs_puts( msg );
}
void makeLCDString()
{
int tmp ;
byte i ;
byte j ;
/* lower */
for ( i = 0 ; i < 16 ; i++ ) {
*(lineL+i) = ' ' ;
}
/* upper */
for ( i = BOTTOM ; i < LAST ; i++ ) {
/* get value */
tmp = *(temp+TOP-i) ;
/* calculate offset */
j = (i << 2) + i ;
/* sign handling */
*(lineU+1+j) = ' ' ;
if ( tmp < 0 ) {
*(lineU+1+j) = '-' ;
tmp *= (-1);
}
/* x1 */
*(lineU+3+j) = tmp % 10 + '0' ;
/* x10 */
tmp /= 10 ;
*(lineU+2+j) = tmp % 10 + '0' ;
}
/* day or night */
*(lineU+15) = '_' ;
if ( dflag ) { *(lineU+15) = '*' ; }
}
void oneShot()
{
rs_putchar('T'); rs_print( *(temp+TOP) ); rs_putchar(' ');
rs_putchar('M'); rs_print( *(temp+MIDDLE) ); rs_putchar(' ');
rs_putchar('B'); rs_print( *(temp+BOTTOM) ); rs_putchar(' ');
rs_print( *(temp+LAST) ); crlf();
}
void ledProc(byte x)
{
/* turn off */
PORTB &= ~(1 << LED_BIT);
/* judge */
if ( x ) { PORTB |= (1 << LED_BIT); }
}
byte convBCD2HEX(byte x)
{
byte result ;
/* lower */
result = (x & 15) ;
/* upper */
result += (((x >> 4) & 15) * 10);
return result ;
}
byte convHEX2BCD(byte x)
{
byte result ;
/* lower */
result = (x % 10);
/* upper */
result += ((x / 10) << 4);
return result ;
}
void put_light_dark()
{
/* get state */
adv = analogRead( LAST );
*(temp+3) = adv ;
/* default (night) */
dflag = OFF ;
/* day */
if ( adv > YLIMIT ) { dflag = ON ; }
}
/* receive interrupt */
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
プログラム容量は、30%(最大容量16kバイト)となってます。
Personal Computerのアプリケーションで、設定温度を超えたとき
警報を出します。Arduinoスケッチは、警報を出す機能を削除して
あります。
Personal Computerには、RaspberryPiを利用します。
表示器を使い、GPIOでシリアルを使ってXBeeに接続。
RaspberryPiの選定理由は、以下。
- 温度湿度は24時間測定するので、低消費電力でなければならない
- ノートPCよりも小さく、設置場所を選ばない
- 24時間の測定データを、Personal Computerの2次記憶に保存したい
- MicrosoftOfficeシリーズExcel相当のspreadsheetでグラフ描画できる機能をもつ
- Internetへ情報公開できるサーバーの役割を担わせたい
RaspberryPiはUnixOSを採用しているので、周期的な
動作は、cronでスクリプトを呼び出し実現できます。
crontabに設定する内容は、以下。
0-58/2 * * * * * /home/pi/adatalog.sh
シェルスクリプト adatalog.sh を使います。
2分ごとに動作シーケンスを実現する仕様を
考えました。
シェルスクリプトの動作シーケンスは、以下。
- 温湿度計測装置からデータを吸い上げ(XBee経由)
- データをテキストファイルに追加書込み
- テキストファイルをCSV形式にしてコピー
- テキストファイルのデータから表示器にグラフ描画
- 設定温度を超えていれば、管理者にメールを発信
- ログファイル更新
グラフ描画ではgnuplotを利用し、それ以外は
PythonかBシェルのコードで対応します。
シーケンスを図示すると、次のようになります。
データをテキストファイルに保存後、CSV形式の
ファイルを作成しておくと、後でspreadsheetを
使ったデータ整理とグラフ描画が可能に。
ログは、交信記録日誌で温湿度記録時間と
緊急警報メールの送信日時を保存します。
XBeeは、送信時に電力を食うので、次のように
DTB(Data Transfer Box)とArduinoを接続して
2台のXBeeでの通信を担当する仕様としました。
DTBをArduinoで実現する場合のスケッチは、以下。
/*
dtb.ino
Data Transfer Box
Pin assignment
PORTB
PB5 (output) TxD2
PB4 (input) RxD2
PB3 (output) TxD1
PB2 (input) RxD1
PB1 (output) TxD0
PB0 (input) RxD0
PORTC
PC5 (output) --
PC4 (output) --
PC3 (output) --
PC2 (output) --
PC1 (output) --
PC0 (output) --
PORTD
PD7 (output)
PD6 (output)
PD5 (output)
PD4 (output)
PD3 (output)
PD2 (output)
PD1 (output) TxD
PD0 (input) RxD
*/
#include <MsTimer2.h>
#include <SoftwareSerial.h>
SoftwareSerial ss_serz( 8, 9); /* rx, tx */
SoftwareSerial ss_sero(10,11); /* rx, tx */
SoftwareSerial ss_sert(12,13); /* rx, tx */
#define OFF 0
#define ON OFF+1
/* pin assignment */
#define BOTTOM 0
#define MIDDLE 1
#define TOP 2
#define LAST 3
#define LED_BIT 5
#define XINTERVAL 2000
#define RSIZE 8
#define BSIZE 256
/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void oneShot(byte x);
void init_ssbuf();
void perform(byte x);
void performCH0();
void performCH1();
void performCH2();
/* variables */
boolean tflag ;
boolean eflag ;
boolean uflag ;
char sbuf[8] ;
byte sindex ;
byte state ;
byte cmd ;
byte xcnt ;
byte ii ;
char rcvz[20] ;
char rcvo[20] ;
char rcvt[32] ;
void setup()
{
/* initialize serial */
Serial.begin(9600);
sindex = 0 ;
rs_puts("Hello !");
crlf();
/* clear flags */
tflag = OFF ;
eflag = OFF ;
uflag = OFF ;
/* initialize port values */
PORTB = 0x00 ;
PORTC = 0x00 ;
PORTD = 0x00 ;
/* initialize port direction */
DDRB = 0xea ;
DDRC = 0xff ;
DDRD = 0xfe ;
/* enable each software serial I/F */
ss_serz.begin(9600);
ss_sero.begin(9600);
ss_sert.begin(9600);
/* initialize buffer */
init_ssbuf();
/* variables */
xcnt = 0 ;
state = 0 ;
/* 1500ms period */
MsTimer2::set(XINTERVAL,update_trigger);
/* enable */
MsTimer2::start();
}
void loop()
{
/* command interpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* one shot ch0 */
if ( cmd == 'Z' ) { oneShot(0); }
/* one shot ch1 */
if ( cmd == 'O' ) { oneShot(1); }
/* one shot ch2 */
if ( cmd == 'T' ) { oneShot(2); }
}
/* timer handling */
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* handling */
perform( state );
/* update state */
state++ ;
if ( state == 3 ) { state = 0 ; }
}
}
void update_trigger()
{
/* set flag */
if ( xcnt & ON ) { tflag = ON ; }
/* inrement */
xcnt++ ;
}
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("Z one shot ch0") ; crlf();
rs_puts("O one shot ch1") ; crlf();
rs_puts("T one shot ch2") ; crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void oneShot(byte x)
{
/* skip if no correct condition */
if ( x > 2 ) return ;
/* channel 0 */
if ( x == 0 ) { rs_puts( rcvz ); }
/* channel 1 */
if ( x == 1 ) { rs_puts( rcvo ); }
/* channel 2 */
if ( x == 2 ) { rs_puts( rcvt ); }
/* new line */
crlf();
}
void perform(byte x)
{
if ( x == 0 ) { performCH0(); }
if ( x == 1 ) { performCH1(); }
if ( x == 2 ) { performCH2(); }
}
void performCH0()
{
char xch ;
/* clear buffer */
for ( ii = 0 ; ii < 20 ; ii++ ) {
*(rcvz+ii) = '\0';
}
/* enable receive */
ss_serz.listen();
/* send command */
ss_serz.println("T");
/* get strings */
for ( ii = 0 ; ii < 19 ; ii++ ) {
if ( ss_serz.available() > 0 ) {
xch = ss_serz.read();
*(rcvz+ii) = xch ;
if ( xch == 0x0d ) { *(rcvz+ii) = '.' ; }
}
delay(1);
}
}
void performCH1()
{
char xch ;
/* clear buffer */
for ( ii = 0 ; ii < 20 ; ii++ ) {
*(rcvo+ii) = '\0';
}
/* enable receive */
ss_sero.listen();
/* send command */
ss_sero.println("T");
/* get strings */
for ( ii = 0 ; ii < 19 ; ii++ ) {
if ( ss_sero.available() > 0 ) {
xch = ss_sero.read();
*(rcvo+ii) = xch ;
if ( xch == 0x0d ) { *(rcvo+ii) = '.' ; }
}
delay(1);
}
}
void performCH2()
{
char xch ;
/* clear buffer */
for ( ii = 0 ; ii < 32 ; ii++ ) {
*(rcvt+ii) = '\0';
}
/* enable receive */
ss_sert.listen();
/* send command */
ss_sert.println("T");
/* get strings */
for ( ii = 0 ; ii < 31 ; ii++ ) {
if ( ss_sert.available() > 0 ) {
xch = ss_sert.read();
*(rcvt+ii) = xch ;
if ( xch == 0x0d ) { *(rcvt+ii) = '.' ; }
}
delay(1);
}
}
void init_ssbuf()
{
*(rcvz+0) = 'Z' ;
*(rcvz+1) = 'z' ;
*(rcvz+2) = '.' ;
*(rcvz+3) = '\0' ;
*(rcvo+0) = 'O' ;
*(rcvo+1) = 'o' ;
*(rcvo+2) = '.' ;
*(rcvo+3) = '\0' ;
*(rcvt+0) = 'T' ;
*(rcvt+1) = 't' ;
*(rcvt+2) = '.' ;
*(rcvt+3) = '\0' ;
}
/* receive interrupt */
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
ソフトウエアシリアルインタフェースを利用
しているので、ハードウエアの方では受信に
割込みを使えますが、ソフトウエアの場合は
コマンドを送ってから、受信待ちをします。
3チャネル分の温度計測装置、温湿度計測装置と
接続できます。温湿度計測装置は、チャネル2に
固定。
チャネルごとに専用受信バッファを用意し、通信で
各チャネルの温度湿度データ要求があったときだけ
内容を公開しています。
温度計測装置のスケッチは、以下。
/*
themfx.ino
Pin assignment
PORTB
PB5 (output) LED
PB4 (output) --
PB3 (output) --
PB2 (output) --
PB1 (output) --
PB0 (output) --
PORTC
PC5 (output)
PC4 (output)
PC3 (output) light sensor
PC2 (output) sensor 2(TOP)
PC1 (output) sensor 1(MIDDLE)
PC0 (output) sensor 0(BOTTOM)
PORTD
PD7 (output) D7
PD6 (output) D6
PD5 (output) D5
PD4 (output) D4
PD3 (output) E
PD2 (output) RS
PD1 (output) TxD
PD0 (input) RxD
*/
#include <MsTimer2.h>
#include <LiquidCrystal.h>
#include <SoftwareSerial.h>
#define OFF 0
#define ON OFF+1
/* pin assignment */
#define BOTTOM 0
#define MIDDLE 1
#define TOP 2
#define LAST 3
#define LED_BIT 5
#define XINTERVAL 1500
#define XLIMIT 35
#define YLIMIT 170
#define RSIZE 8
#define BSIZE 256
/* LCD rs , e , D4 , D5 , D6 , D7 */
LiquidCrystal lcd( 2, 3, 4, 5, 6, 7 );
SoftwareSerial sw_ser( 8, 9); /* rx, tx */
/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void convert_digit();
void makeLCDString();
void oneShot();
void oneShotX();
void put_light_dark();
/* variables */
boolean tflag ;
boolean uflag ;
boolean oflag ;
boolean dflag ; /* day or night */
boolean lflag ;
char sbuf[4] ;
byte sindex ;
byte cmd ;
int adv ;
int tv ;
int temp[4] ;
char lineU[17];
char tbuf[17];
void setup()
{
/* initialize serial */
Serial.begin(9600);
sindex = 0 ;
rs_puts("Hello !");
crlf();
sw_ser.begin(9600);
sw_ser.listen();
/* clear flags */
tflag = OFF ;
uflag = OFF ;
oflag = ON ;
dflag = OFF ;
lflag = OFF ;
/* initialize port values */
PORTB = 0x00 ;
PORTC = 0x00 ;
PORTD = 0x00 ;
/* initialize port direction */
DDRB = 0xfe ;
DDRC = 0x00 ;
DDRD = 0xfe ;
/* 1500ms period */
MsTimer2::set(XINTERVAL,update_trigger);
/* enable */
MsTimer2::start();
/* initialize LCD */
lcd.begin( 16, 2 );
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Measure");
lcd.setCursor(0, 1);
lcd.print("Hello, world!");
/* LCD string default */
for ( byte ii = 0 ; ii < 16 ; ii++ ) {
*(lineU+ii) = ' ' ;
}
*(lineU+ 0) = 'T';
*(lineU+ 4) = '|';
*(lineU+ 5) = 'M';
*(lineU+ 9) = '|';
*(lineU+10) = 'B';
*(lineU+14) = '|';
*(lineU+15) = 'N';
*(lineU+16) = '\0';
}
void loop()
{
char xch ;
/* one time handling */
if ( oflag == ON ) {
/* clear flag */
oflag = OFF ;
/* default */
lcd.setCursor(0,1);
lcd.print("Namara Firm ");
lflag = ON ;
}
/* command interpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* one shot */
if ( cmd == 'T' ) { oneShot(); }
/* new line */
crlf() ;
}
/* timer handling */
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* get thermometer */
for ( int ii = TOP ; ii > -1 ; ii-- ) {
/* get data */
adv = analogRead(ii);
/* convert (voltage) */
tv = map(adv,0,1023,0,5000);
/* convert (temparature) */
*(temp+ii) = map(tv,300,1600,-30,100);
}
/* light or dark */
put_light_dark();
/* convert */
convert_digit();
/* show ( LCD ) */
makeLCDString();
lcd.setCursor(0,0); lcd.print( lineU );
if ( lflag == ON ) {
lflag = OFF ;
lcd.setCursor(0,1); lcd.print(" ");
}
}
/* software serial handling */
if ( sw_ser.available() ) {
xch = sw_ser.read();
/* one shot handling */
if ( xch == 'T' ) { oneShotX(); }
}
}
void update_trigger()
{
/* set flag */
tflag = ON ;
}
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("T one shot"); crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void convert_digit()
{
byte ii ;
byte j ;
byte k ;
int tmp ;
char xx[3];
/* clear buffer */
for ( ii = 0 ; ii < 17 ; ii++ ) {
*(tbuf+ii) = ' ' ;
}
*(tbuf+16) = '\0' ;
/* top */
for ( j = 0 ; j < 4 ; j++ ) {
/* integer -> digit */
tmp = *(temp+j) ;
for ( ii = 0 ; ii < 3 ; ii++ ) {
k = 2 - ii ;
*(xx+k) = tmp % 10 ;
tmp /= 10 ;
}
/* zero surpress */
k = 4 * j ;
for ( ii = 0 ; ii < 3 ; ii++ ) {
*(tbuf+1+ii+k) = *(xx+ii) + '0' ;
}
if ( *(xx+0) == 0 ) {
*(tbuf+1+k) = ' ' ;
if ( *(xx+1) == 0 ) {
*(tbuf+2+k) = ' ' ;
}
}
}
}
void makeLCDString()
{
/* TOP */
*(lineU+1) = *(tbuf+1);
*(lineU+2) = *(tbuf+2);
*(lineU+3) = *(tbuf+3);
/* MIDDLE */
*(lineU+6) = *(tbuf+5);
*(lineU+7) = *(tbuf+6);
*(lineU+8) = *(tbuf+7);
/* BOTTOM */
*(lineU+11) = *(tbuf+ 9);
*(lineU+12) = *(tbuf+10);
*(lineU+13) = *(tbuf+11);
/* day or night */
*(lineU+15) = '_' ;
if ( dflag ) { *(lineU+15) = '*' ; }
}
void oneShot()
{
rs_puts( tbuf );
crlf();
}
void oneShotX()
{
sw_ser.println( tbuf );
}
void put_light_dark()
{
/* get state */
adv = analogRead( LAST );
*(temp+3) = adv ;
/* default (night) */
dflag = OFF ;
/* day */
if ( adv > YLIMIT ) { dflag = ON ; }
}
/* receive interrupt */
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
温湿度計測装置のスケッチは、次のように定義。
/*
thermfy.ino
Pin assignment
PORTB
PB5 (output) --
PB4 (output) --
PB3 (output) --
PB2 (output) sensor 2(TOP)
PB1 (output) sensor 1(MIDDLE)
PB0 (output) sensor 0(BOTTOM)
PORTC
PC5 (output)
PC4 (output)
PC3 (output) light sensor
PC2 (output)
PC1 (output)
PC0 (output)
PORTD
PD7 (output) D7
PD6 (output) D6
PD5 (output) D5
PD4 (output) D4
PD3 (output) E
PD2 (output) RS
PD1 (output) TxD
PD0 (input) RxD
*/
#include <MsTimer2.h>
#include <LiquidCrystal.h>
#include <TroykaDHT.h>
#include <SoftwareSerial.h>
#define OFF 0
#define ON OFF+1
/* pin assignment */
#define BOTTOM 0
#define MIDDLE 1
#define TOP 2
#define LAST 3
#define XINTERVAL 1000
#define XLIMIT 35
#define YLIMIT 170
#define RSIZE 16
#define BSIZE 256
/* LCD rs , e , D4 , D5 , D6 , D7 */
LiquidCrystal lcd( 2, 3, 4, 5, 6, 7 );
SoftwareSerial sw_ser(11,12); /* rx, tx */
/* sensor */
#define PIN_DHT_B 8
#define PIN_DHT_M 9
#define PIN_DHT_T 10
DHT dhtB(PIN_DHT_B,DHT11);
DHT dhtM(PIN_DHT_M,DHT11);
DHT dhtT(PIN_DHT_T,DHT11);
/* function prototype */
void update_trigger();
void show_help();
void rs_putchar(char x);
void rs_puts(char *ptr);
void crlf();
void convert_digit();
void makeLCDString();
void oneShot();
void oneShotX();
void put_light_dark();
/* variables */
boolean tflag ;
boolean uflag ;
boolean oflag ;
boolean dflag ; /* day or night */
char sbuf[16] ;
byte sindex ;
byte cmd ;
int adv ;
int temp[7] ;
char lineU[17];
char lineL[17];
char tbuf[29];
void setup()
{
/* initialize serial */
Serial.begin(9600);
sindex = 0 ;
rs_puts("Hello !");
crlf();
show_help();
sw_ser.begin(9600);
sw_ser.listen();
/* clear flags */
tflag = OFF ;
uflag = OFF ;
oflag = ON ;
dflag = OFF ;
/* initialize port values */
PORTB = 0x00 ;
PORTC = 0x00 ;
PORTD = 0x00 ;
/* initialize port direction */
DDRB = 0xf7 ;
DDRC = 0x00 ;
DDRD = 0xfe ;
/* 1000ms period */
MsTimer2::set(XINTERVAL,update_trigger);
/* enable */
MsTimer2::start();
/* initialize LCD */
lcd.begin( 16, 2 );
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Measure");
lcd.setCursor(0, 1);
lcd.print("Hello, world!");
/* LCD string default */
for ( byte ii = 0 ; ii < 16 ; ii++ ) { *(lineU+ii) = ' ' ; }
*(lineU+ 0) = 'T';
*(lineU+ 4) = '|';
*(lineU+ 5) = 'M';
*(lineU+ 9) = '|';
*(lineU+10) = 'B';
*(lineU+14) = '|';
*(lineU+15) = 'N';
*(lineU+16) = '\0';
*(lineL+ 0) = 't';
*(lineL+ 4) = '|';
*(lineL+ 5) = 'm';
*(lineL+ 9) = '|';
*(lineL+10) = 'b';
*(lineL+16) = '\0';
/* enable humidity sensors */
dhtB.begin();
dhtM.begin();
dhtT.begin();
}
void loop()
{
char xch ;
float humidity ;
float temperature ;
/* one time handling */
if ( oflag == ON ) {
/* clear flag */
oflag = OFF ;
/* default */
lcd.setCursor(0,1);
lcd.print("Namara Firm ");
}
/* command interpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* get command */
cmd = *(sbuf+0) ;
/* help */
if ( cmd == '?' ) { show_help(); }
/* one shot */
if ( cmd == 'T' ) { oneShot(); }
/* new line */
crlf() ;
}
/* timer handling */
if ( tflag == ON ) {
/* clear flag */
tflag = OFF ;
/* get thermometer and humidity */
for ( int ii = TOP ; ii > -1 ; ii-- ) {
/* get data */
if ( ii == TOP ) {
dhtT.read();
if ( dhtM.getState() == DHT_OK ) {
humidity = dhtT.getHumidity();
temperature = dhtT.getTemperatureC();
}
}
if ( ii == MIDDLE ) {
dhtM.read();
if ( dhtM.getState() == DHT_OK ) {
humidity = dhtM.getHumidity();
temperature = dhtM.getTemperatureC();
}
}
if ( ii == BOTTOM ) {
dhtB.read();
if ( dhtB.getState() == DHT_OK ) {
humidity = dhtB.getHumidity();
temperature = dhtB.getTemperatureC();
}
}
/* convert */
*(temp+ii ) = (int)temperature ;
*(temp+ii+4) = (int)humidity ;
}
/* light or dark */
put_light_dark();
/* convert */
convert_digit();
/* show ( LCD ) */
makeLCDString();
lcd.setCursor(0,0); lcd.print( lineU );
lcd.setCursor(0,1); lcd.print( lineL );
}
/* software serial handling */
if ( sw_ser.available() ) {
xch = sw_ser.read();
/* one shot handling */
if ( xch == 'T' ) { oneShotX(); }
}
}
void update_trigger()
{
/* set flag */
tflag = ON ;
}
void show_help()
{
rs_puts("? help") ; crlf();
rs_puts("T one shot") ; crlf();
}
void rs_putchar(char x)
{
Serial.write(x);
}
void rs_puts(char *ptr)
{
while ( *ptr ) {
rs_putchar( *ptr );
ptr++;
}
}
void crlf()
{
rs_putchar('\r');
rs_putchar('\n');
}
void convert_digit()
{
byte ii ;
byte j ;
byte k ;
int tmp ;
char xx[3];
/* clear buffer */
for ( ii = 0 ; ii < 29 ; ii++ ) {
*(tbuf+ii) = ' ' ;
}
*(tbuf+28) = '\0' ;
/* thermometer */
for ( j = 0 ; j < 4 ; j++ ) {
/* integer -> digit */
tmp = *(temp+j) ;
for ( ii = 0 ; ii < 3 ; ii++ ) {
k = 2 - ii ;
*(xx+k) = tmp % 10 ;
tmp /= 10 ;
}
/* zero surpress */
k = 4 * j ;
for ( ii = 0 ; ii < 3 ; ii++ ) {
*(tbuf+1+ii+k) = *(xx+ii) + '0' ;
}
if ( *(xx+0) == 0 ) {
*(tbuf+1+k) = ' ' ;
if ( *(xx+1) == 0 ) {
*(tbuf+2+k) = ' ' ;
}
}
}
/* humidity */
for ( j = 4 ; j < 7 ; j++ ) {
/* integer -> digit */
tmp = *(temp+j) ;
for ( ii = 0 ; ii < 3 ; ii++ ) {
k = 2 - ii ;
*(xx+k) = tmp % 10 ;
tmp /= 10 ;
}
/* zero surpress */
k = 4 * j ;
for ( ii = 0 ; ii < 3 ; ii++ ) {
*(tbuf+1+ii+k) = *(xx+ii) + '0' ;
}
if ( *(xx+0) == 0 ) {
*(tbuf+1+k) = ' ' ;
if ( *(xx+1) == 0 ) {
*(tbuf+2+k) = ' ' ;
}
}
}
}
void makeLCDString()
{
/* TOP */
*(lineU+1) = *(tbuf+1);
*(lineU+2) = *(tbuf+2);
*(lineU+3) = *(tbuf+3);
/* MIDDLE */
*(lineU+6) = *(tbuf+5);
*(lineU+7) = *(tbuf+6);
*(lineU+8) = *(tbuf+7);
/* BOTTOM */
*(lineU+11) = *(tbuf+ 9);
*(lineU+12) = *(tbuf+10);
*(lineU+13) = *(tbuf+11);
/* day or night */
*(lineU+15) = '_' ;
if ( dflag ) { *(lineU+15) = '*' ; }
/* TOP */
*(lineL+1) = *(tbuf+17);
*(lineL+2) = *(tbuf+18);
*(lineL+3) = *(tbuf+19);
/* MIDDLE */
*(lineL+6) = *(tbuf+21);
*(lineL+7) = *(tbuf+22);
*(lineL+8) = *(tbuf+23);
/* BOTTOM */
*(lineL+11) = *(tbuf+25);
*(lineL+12) = *(tbuf+26);
*(lineL+13) = *(tbuf+27);
}
void oneShot()
{
rs_puts( tbuf );
crlf();
}
void oneShotX()
{
sw_ser.println( tbuf );
}
void put_light_dark()
{
/* get state */
adv = analogRead( LAST );
*(temp+3) = adv ;
/* default (night) */
dflag = OFF ;
/* day */
if ( adv > YLIMIT ) { dflag = ON ; }
}
/* receive interrupt */
void serialEvent()
{
char ch;
if ( Serial.available() > 0 ) {
/* get 1 character */
ch = Serial.read();
/* store */
*(sbuf+sindex) = ch ;
/* increment */
sindex++ ;
/* judge */
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
温度計測装置と温湿度計測装置の中にあるArduinoスケッチでは
EEPROMとReal Time Clockへの対応を除いたので、プログラムの
容量は、全体の30%から50%となっています。
また、消費電力も大幅に低下したので、電池の交換回数が隔日から
3日に1度にまで減りました。
DTBでの電力消費が激しいので、鉛蓄電池を電源に使います。
選択した鉛蓄電池は、以下。
電池は、ビニルハウス入口の外に置いて、内部の土壌を
汚染しないようにします。(赤マーク位置に設置)
母屋におくコンピュータの画面は、以下。
左側にDTBから収集した温度、湿度の数値を表示し
右側に、温度、湿度の上限と下限を入れて警報を
出すための閾値を設定します。
中央から下には、温度と湿度の変化をグラフで
リアルタイムに表示。
通信を除き、情報はファイルから入力して
グラフ描画するPythonコードは、以下。
import sys
import tkinter as tk
#*********************
# generate window
#*********************
root = tk.Tk()
root.title('Green House NAMARA Firm')
root.geometry('620x460')
#+++++++++++
# load
#+++++++++++
fxtop = []
fxmid = []
fxbot = []
with open('xdat.txt','r') as fd :
for e in fd.read().splitlines():
tmp = []
xx = e.split()
for ee in xx:
tmp.append( int(ee) )
tmpx = []
tmpy = []
tmpz = []
tmpx.append(tmp[0])
tmpx.append(tmp[3])
tmpy.append(tmp[1])
tmpy.append(tmp[3])
tmpz.append(tmp[2])
tmpz.append(tmp[3])
fxtop.append( tmpx )
fxmid.append( tmpy )
fxbot.append( tmpz )
fytop = []
fymid = []
fybot = []
with open('ydat.txt','r') as fd :
for e in fd.read().splitlines():
tmp = []
xx = e.split()
for ee in xx:
tmp.append( int(ee) )
tmpx = []
tmpy = []
tmpz = []
tmpx.append(tmp[0])
tmpx.append(tmp[3])
tmpy.append(tmp[1])
tmpy.append(tmp[3])
tmpz.append(tmp[2])
tmpz.append(tmp[3])
fytop.append( tmpx )
fymid.append( tmpy )
fybot.append( tmpz )
fztop = []
fzmid = []
fzbot = []
with open('zdat.txt','r') as fd :
for e in fd.read().splitlines():
tmp = []
xx = e.split()
for ee in xx:
tmp.append( int(ee) )
tmpx = []
tmpy = []
tmpz = []
tmpx.append(tmp[0])
tmpx.append(tmp[3])
tmpy.append(tmp[1])
tmpy.append(tmp[3])
tmpz.append(tmp[2])
tmpz.append(tmp[3])
fztop.append( tmpx )
fzmid.append( tmpy )
fzbot.append( tmpz )
#*********************
# frame
#*********************
frmL = tk.Frame(root)
frmL.grid(row=0,column=0)
frmR = tk.Frame(root)
frmR.grid(row=0,column=3)
frmCH0T = tk.Frame(root)
frmCH0T.grid(row=7,column=1)
frmCH0M = tk.Frame(root)
frmCH0M.grid(row=8,column=1)
frmCH0B = tk.Frame(root)
frmCH0B.grid(row=9,column=1)
frmCH1T = tk.Frame(root)
frmCH1T.grid(row=7,column=2)
frmCH1M = tk.Frame(root)
frmCH1M.grid(row=8,column=2)
frmCH1B = tk.Frame(root)
frmCH1B.grid(row=9,column=2)
frmCH2T = tk.Frame(root)
frmCH2T.grid(row=7,column=3)
frmCH2M = tk.Frame(root)
frmCH2M.grid(row=8,column=3)
frmCH2B = tk.Frame(root)
frmCH2B.grid(row=9,column=3)
#*********************
# unit
#*********************
lblUnit1 = tk.Label(frmL,text = 'Celsius')
lblUnit1.grid(row = 0, column = 1)
lblUnit2 = tk.Label(frmL,text = 'Celsius')
lblUnit2.grid(row = 0, column = 2)
lblUnit3 = tk.Label(frmL,text = '%')
lblUnit3.grid(row = 0, column = 3)
lblUnit4 = tk.Label(frmR,text = 'Celsius')
lblUnit4.grid(row = 0, column = 1)
lblUnit5 = tk.Label(frmR,text = '%')
lblUnit5.grid(row = 0, column = 2)
lblTop = tk.Label(frmL,text = 'TOP')
lblTop.grid(row = 1, column = 0)
lblMid = tk.Label(frmL,text = 'MIDDLE')
lblMid.grid(row = 2, column = 0)
lblBot = tk.Label(frmL,text = 'BOTTOM')
lblBot.grid(row = 3, column = 0)
#*********************
# channel 0 parameters
#*********************
ch0TopVal = 28
ch0MidVal = 29
ch0BotVal = 29
lblCh0Top = tk.Label(frmL,text = str(ch0TopVal) )
lblCh0Top.grid(row = 1, column = 1)
lblCh0Mid = tk.Label(frmL,text = str(ch0MidVal))
lblCh0Mid.grid(row = 2, column = 1)
lblCh0Bot = tk.Label(frmL,text = str(ch0BotVal))
lblCh0Bot.grid(row = 3, column = 1)
#*********************
# channel 1 parameters
#*********************
ch1TopVal = 28
ch1MidVal = 27
ch1BotVal = 30
lblCh1Top = tk.Label(frmL,text = str(ch1TopVal) )
lblCh1Top.grid(row = 1, column = 2)
lblCh1Mid = tk.Label(frmL,text = str(ch1MidVal))
lblCh1Mid.grid(row = 2, column = 2)
lblCh1Bot = tk.Label(frmL,text = str(ch1BotVal))
lblCh1Bot.grid(row = 3, column = 2)
#*********************
# channel 2 parameters
#*********************
ch2TopVal = 72
ch2MidVal = 80
ch2BotVal = 79
lblCh2Top = tk.Label(frmL,text = str(ch2TopVal) )
lblCh2Top.grid(row = 1, column = 3)
lblCh2Mid = tk.Label(frmL,text = str(ch2MidVal))
lblCh2Mid.grid(row = 2, column = 3)
lblCh2Bot = tk.Label(frmL,text = str(ch2BotVal))
lblCh2Bot.grid(row = 3, column = 3)
#*********************
# item labels
#*********************
lblChTL = tk.Label(root,text= 'thermometer')
lblChTL.grid(row=6,column=1)
lblChML = tk.Label(root,text= 'thermometer')
lblChML.grid(row=6,column=2)
lblChBL = tk.Label(root,text= 'humidity')
lblChBL.grid(row=6,column=3)
lblCh0Lable = tk.Label(root,text = 'TOP' )
lblCh0Lable.grid(row = 7, column = 0)
lblCh1Lable = tk.Label(root,text = 'MIDDLE' )
lblCh1Lable.grid(row = 8, column = 0)
lblCh2Lable = tk.Label(root,text = 'BOTTOM' )
lblCh2Lable.grid(row = 9, column = 0)
#*********************
# limit parameters
#*********************
tUpper = 40
tLower = 2
hUpper = 95
hLower = 20
lblTUpper = tk.Label(frmR,text = 'Upper' )
lblTUpper.grid(row = 1, column = 0)
lblTLower = tk.Label(frmR,text = 'Lower' )
lblTLower.grid(row = 2, column = 0)
entTUpper = tk.Entry(frmR,width=4)
entTUpper.insert(tk.END,str(tUpper))
entTUpper.grid(row = 1, column = 1)
entTLower = tk.Entry(frmR,width=4)
entTLower.insert(tk.END,str(tLower))
entTLower.grid(row = 2, column = 1)
entHUpper = tk.Entry(frmR,width=4)
entHUpper.insert(tk.END,str(hUpper))
entHUpper.grid(row = 1, column = 2)
entHLower = tk.Entry(frmR,width=4)
entHLower.insert(tk.END,str(hLower))
entHLower.grid(row = 2, column = 2)
#*********************
# functions
#*********************
def setTemp() :
utemp = entTUpper.get()
ltemp = entTLower.get()
#print( str(utemp) + ' ' + str(ltemp) )
tUpper = utemp
tLower = ltemp
entTUpper.delete(0,tk.END)
entTLower.delete(0,tk.END)
entTUpper.insert(tk.END,str(tUpper))
entTLower.insert(tk.END,str(tLower))
def setHumi():
uhumi = entHUpper.get()
lhumi = entHLower.get()
#print( str(uhumi) + ' ' + str(lhumi) )
hUpper = uhumi
hLower = lhumi
entHUpper.delete(0,tk.END)
entHLower.delete(0,tk.END)
entHUpper.insert(tk.END,str(hUpper))
entHLower.insert(tk.END,str(hLower))
def myExit():
exit()
#*********************
# Canvas object
#*********************
wx = 140
wh = 100
dcol = 'lightgray'
canCH0T = tk.Canvas(frmCH0T,bg = dcol, width = wx , height = wh )
canCH0T.grid(row=0,column=0)
canCH0M = tk.Canvas(frmCH0M,bg = dcol, width = wx , height = wh )
canCH0M.grid(row=0,column=0)
canCH0B = tk.Canvas(frmCH0B,bg = dcol, width = wx , height = wh )
canCH0B.grid(row=0,column=0)
canCH1T = tk.Canvas(frmCH1T,bg = dcol, width = wx , height = wh )
canCH1T.grid(row=0,column=0)
canCH1M = tk.Canvas(frmCH1M,bg = dcol, width = wx , height = wh )
canCH1M.grid(row=0,column=0)
canCH1B = tk.Canvas(frmCH1B,bg = dcol, width = wx , height = wh )
canCH1B.grid(row=0,column=0)
canCH2T = tk.Canvas(frmCH2T,bg = dcol, width = wx , height = wh )
canCH2T.grid(row=0,column=0)
canCH2M = tk.Canvas(frmCH2M,bg = dcol, width = wx , height = wh )
canCH2M.grid(row=0,column=0)
canCH2B = tk.Canvas(frmCH2B,bg = dcol, width = wx , height = wh )
canCH2B.grid(row=0,column=0)
def canCH012draw(which,dx,dy,dz):
# set color
ccol = 'green'
# top
last = len( dx ) - 1
for e in range(0,last) :
# generate x axis values
xs = e
xd = xs + 1
# get value from list
tmpx0 = dx[e]
tmpx1 = dx[e+1]
tmpy0 = dy[e]
tmpy1 = dy[e+1]
tmpz0 = dz[e]
tmpz1 = dz[e+1]
# generate y axis values
yx = []
tmp = 100 - tmpx0[0]
if which < 2 :
tmp = tmp - tmpx0[0]
yx.append( tmp )
yx.append( 100 - 2 * tmpx0[1] )
tmp = 100 - tmpx1[0]
if which < 2 :
tmp = tmp - tmpx1[0]
yx.append( tmp )
yx.append( 100 - 2 * tmpx1[1] )
yy = []
tmp = 100 - tmpy0[0]
if which < 2 :
tmp = tmp - tmpy0[0]
yy.append( tmp )
yy.append( 100 - 2 * tmpy0[1] )
tmp = 100 - tmpy1[0]
if which < 2 :
tmp = tmp - tmpy1[0]
yy.append( tmp )
yy.append( 100 - 2 * tmpy1[1] )
yz = []
tmp = 100 - tmpz0[0]
if which < 2 :
tmp = tmp - tmpz0[0]
yz.append( tmp )
yz.append( 100 - 2 * tmpz0[1] )
tmp = 100 - tmpz1[0]
if which < 2 :
tmp = tmp - tmpz1[0]
yz.append( tmp )
yz.append( 100 - 2 * tmpz1[1] )
# draw (top)
pcol = 'blue'
if which == 0 :
canCH0T.create_line(xs,yx[0],xd,yx[2],fill=pcol,width=2)
canCH0T.create_line(xs,yx[1],xd,yx[3],fill=ccol,width=2)
if which == 1 :
canCH1T.create_line(xs,yx[0],xd,yx[2],fill=pcol,width=2)
canCH1T.create_line(xs,yx[1],xd,yx[3],fill=ccol,width=2)
if which == 2:
canCH2T.create_line(xs,yx[0],xd,yx[2],fill=pcol,width=2)
canCH2T.create_line(xs,yx[1],xd,yx[3],fill=ccol,width=2)
# draw (middle)
pcol = 'red'
if which == 0 :
canCH0M.create_line(xs,yy[0],xd,yy[2],fill=pcol,width=2)
canCH0M.create_line(xs,yy[1],xd,yy[3],fill=ccol,width=2)
if which == 1 :
canCH1M.create_line(xs,yx[0],xd,yx[2],fill=pcol,width=2)
canCH1M.create_line(xs,yx[1],xd,yx[3],fill=ccol,width=2)
if which == 2 :
canCH2M.create_line(xs,yx[0],xd,yx[2],fill=pcol,width=2)
canCH2M.create_line(xs,yx[1],xd,yx[3],fill=ccol,width=2)
# draw (bottom)
pcol = 'orange'
if which == 0 :
canCH0B.create_line(xs,yz[0],xd,yz[2],fill=pcol,width=2)
canCH0B.create_line(xs,yz[1],xd,yz[3],fill=ccol,width=2)
if which == 1 :
canCH1B.create_line(xs,yz[0],xd,yz[2],fill=pcol,width=2)
canCH1B.create_line(xs,yz[1],xd,yz[3],fill=ccol,width=2)
if which == 2 :
canCH2B.create_line(xs,yz[0],xd,yz[2],fill=pcol,width=2)
canCH2B.create_line(xs,yz[1],xd,yz[3],fill=ccol,width=2)
canCH012draw(0,fxtop,fxmid,fxbot)
canCH012draw(1,fytop,fymid,fybot)
canCH012draw(2,fztop,fzmid,fzbot)
#*********************
# Button object
#*********************
btnExit = tk.Button(frmL, text = 'Exit' , command = myExit )
btnExit.grid(row = 0, column = 0)
btnTempGet = tk.Button(frmR, text = 'Set' , command = setTemp )
btnTempGet.grid(row = 3, column = 1)
btnHumiGet = tk.Button(frmR, text = 'Set' , command = setHumi )
btnHumiGet.grid(row = 3, column = 2)
root.mainloop()
(under construction)
目次
前
次