DreamerDreamのブログ

夢想家の夢です。〜揚げたてのモヤっとしたものをラフレシアと共に〜

RaspberryPiと炊飯器で低温調理器を自作してみた⑤ 「温度取得デーモン」

単純に、センサモジュールから取得出来る値から℃を抽出して共用ファイルに保存するだけのデーモン。

f:id:DreamerDream:20190918163948p:plain

本来、必用なプログラムが各々センサ値を読めば良いのですが、読み出しに時間が少しかかるため、温度取得専用のプログラムから共用ファイルに書き出しおくとスムーズなので今回はこのようにイチイチ書き出すようにしました。

 

<write_tempd.py>

 

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

import file_mng as file
import time

#温度計のセーブファイル

file_temp = '/sys/bus/w1/devices/28-000007248aac/w1_slave'

 

#センサモジュールの値から℃を抽出する
def load_temp():
  data = file.load( file_temp )
  try:
    return str( float( data.split('t=')[1] ) / 1000 )
  except:
    return '-------'

 

#/dev/shm/tempに温度を保存する

def make_temp():
  temp = load_temp()
  file.save_temp( temp )

 

if __name__=='__main__':
  while True:
    make_temp()
    time.sleep(0.5)

 

<全プログラム内部構造一覧>

dreamerdream.hateblo.jp

 

RaspberryPiと炊飯器で低温調理器を自作してみた④ 「画面表示デーモン」

ディスプレイの表示用プログラムです。

画面は今回たまたま手元にあった2色のカラーOLEDディスプレイをを利用しただけで、表示内容をファイルを読んで変えられるようにしただけで表示方法はほぼ以前に書いた記事のまま特に手を加えていません。↓

dreamerdream.hateblo.jp

 

このプログラムが無くてもシステムは問題無く動きますがLED表示とかより画面があった方が機械としてカッコイイので付けることにしました。

 

f:id:DreamerDream:20190918163901p:plain

/dev/shm/領域からデータを読み出してそのまま表示しています。

デーモンで0.5秒ごとに動かしています。

<temp_displayd.py>

 

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

import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

import time

import file_mng as file

 

#トップの文字(青字領域の高さ)
top_y = 14

#タイトル文字(黄色領域の高さ)
title_y = 0

#各行の移動距離
str_size = 10

#文字のX軸のサイズ
str_size_x = 6
# Raspberry Pi pin configuration
RST = 24
disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

text_title='-- Teion Choriki --'

text_main_top='00:00:00 | Tmp:--.--'

 

# Initialize library.
disp.begin()

# Clear display.
disp.clear()
disp.display()

# Create blank image for drawing.
# Make sure to create image with mode '1' for 1-bit color.
width = disp.width
height = disp.height
image = Image.new('1', (width, height))

# Get drawing object to draw on image.
draw = ImageDraw.Draw(image)

# Draw a black filled box to clear the image.
draw.rectangle((0,0,width,height), outline=0, fill=0)

 

#全領域の表示を消す

def clear_all():
  draw.rectangle((0, 0,width, height ), outline=0, fill=0)

#トップ(黄色領域)の表示を消す

def clear_top():
  draw.rectangle((0, 0,width, str_size ), outline=0, fill=0)

#指定行(青文字領域)の表示を消す

def clear_row( row ):
  row = top_y + ( str_size * row )
  draw.rectangle((0, row ,width, row + str_size ), outline=0, fill=0)

#指定行(青文字領域)の表示

def write_row( row ,text ):
  clear_row( row )
  draw.text(( 0 , ( top_y + row * str_size ) ), text, fill=256 )

#トップ(黄色文字領域)の表示

def write_top(text):
  draw.text((0,title_y), text, fill=256)

#実際のディスプレイ描画

def view():
  disp.image(image)
  disp.display()

#立ち上げ時にタイトルを徐々に上に移動させて消すモーション

def remove_title():
  for i in range( str_size ):
    clear_top()
    draw.text( ( 0, -i ), text_title , fill=256)
    view()

#時間表示の部分だけ消して書き換え

def write_time( tim_str ):
  if 0 < len( tim_str ):
    draw.rectangle( ( 0 , title_y , (str_size_x * len(tim_str) ), ( title_y + str_size ) ) , outline=0, fill=0 )
    draw.text(( 0 , title_y ), tim_str , fill=256 )

#温度表示の部分だけ消して書き換え

def write_temp( temp_str ):
  if 0 < len(temp_str):
    draw.rectangle( ( str_size_x * 15 , title_y , ( str_size_x * 15 * len(temp_str) ), ( title_y + str_size ) ) , outline=0, fill=0 )
    draw.text(( str_size_x * 15 , title_y ), temp_str , fill=256 )

 

 

def main():

 #タイトルを表示して
  write_top( text_title )
  view()

  time.sleep(3)

#タイトルをスクロールで消す
  remove_title()

#タイトルを時間と温度表示に書き換えて
  write_top( text_main_top )
  view()

#以降、ファイルを読んで書き換えることを繰り返す

  while True:
    write_time( file.load_time() ) 
    write_temp( file.load_temp() )

    write_row(0, file.load_row_0() )
    write_row(1, file.load_row_1() )
    write_row(2, file.load_row_2() )
    write_row(3, file.load_row_3() )
    write_row(4, file.load_row_4() )

    view()
    time.sleep(0.5)


if __name__=='__main__':
main()

<全プログラム内部構造一覧>

dreamerdream.hateblo.jp

 

RaspberryPiと炊飯器で低温調理器を自作してみた③ 「ファイル統括モジュール」

前回、各種ファイルの説明をしました。

今回はプログラムの中身です。

 

f:id:DreamerDream:20190918163549p:plain

 

<file_mng.py>

これは全てのプログラムから共用するファイルデータを扱います。

(※get、loadが混在している等、突っ込みは無しでお願いします)

 

# -*- coding: utf-8 -*-

import os

dir_shm = '/dev/shm/'

#現在温度
file_temp = dir_shm + 'temp'

#画面表示用タイム

file_time = dir_shm + 'time'

#画面表示_row=行
file_row_0 = dir_shm + 'row_0'
file_row_1 = dir_shm + 'row_1'
file_row_2 = dir_shm + 'row_2'
file_row_3 = dir_shm + 'row_3'
file_row_4 = dir_shm + 'row_4'

#スタートファイル

file_start = dir_shm + 'start'

 

dir_etc = '/usr/local/etc/'

#温度設定ファイル
file_set_temp = dir_etc + 'temp'

#時間設定ファイル
file_set_time = dir_etc + 'time'

 

#ログファイル

dir_log = '/home/machinelog/'

 

def save( filename, text ):
  f = open( filename,'w')
  f.write(text)
  f.close()

 

def load( filename ):
  s = ''
  try:
    f = open( filename, 'r' )
    s = f.read()
    f.close()
    s = s.strip()
  except:
    pass
  return s

 

def remove( filename ):
  os.remove( filename )

 

def is_file( filename ):
  return os.path.isfile( filename )

 

def log( filename, now_temp, power_on ):
  text = str(now_temp) + ',' + str(power_on) + '\n'
  f = open( dir_log + filename, 'a' )
  f.write( text )
  f.close()

 

#温度設定読み出し

def get_temp_set():
  tm = load( file_set_temp )
  if tm == '':
    return '60' #default 60d
  return tm 

#温度設定保存

def save_temp_set( tm ):
  save( file_set_temp, tm )

 

#時間設定読み出し

def get_time_set():
  tm = load( file_set_time )
  if tm == '':
    return '60' # default 60 min
  return tm

#時間設定保存

def save_time_set( tm ):
  save( file_set_time, tm )
 

#スタートファイルの有無

def is_start():
  return is_file( file_start )

#スタートファイル生成

def start( tim ):
  save( file_start, tim )

#ストップ(スタートファイル削除)

def stop():
  remove( file_start )

#スタート時間読み出し

def load_start_time():
  return load( file_start )

 

#現在温度読み出し

def load_temp():
  return load( file_temp )

#現在温度保存
def save_temp( text ):
  save( file_temp , text )

#表示時間読み出し
def load_time():
  return load( file_time )

#表示時間保存
def save_time( text ):
  save( file_time , text )

 

#以下、画面行ごとの表示と保存

def load_row_0():
  return load( file_row_0 )
def save_row_0( text ):
  save( file_row_0 , text)

def load_row_1():
  return load( file_row_1 )
def save_row_1( text ):
  save( file_row_1 , text)

def load_row_2():
  return load( file_row_2 )
def save_row_2( text ):
  save( file_row_2 , text)

def load_row_3():
   return load( file_row_3 )
def save_row_3( text ):
  save( file_row_3 , text)

def load_row_4():

  return load( file_row_4 )
def save_row_4( text ):
  save( file_row_4 , text)

 

 

<全プログラム内部構造一覧>

dreamerdream.hateblo.jp

 

RaspberryPiと炊飯器で低温調理器を自作してみた② プログラムの内部構造 ソフトをデーモンとして分割処理させる

前回、ざっくりした回路を組みましたのでハードは完成です。

dreamerdream.hateblo.jp

 

今回はこの回路を制御する為のラズパイ側のプログラムを機能別に分割していきます。

分割処理させるメリットとして

  • 後で機能を追加したりしやすくなる。
  • 温度の取得とか画面の表示とか実行が遅いプログラムの待ち時間を発生させない。
  • 後で簡単に使い回しが出来るプログラムになる。

ことが挙げられます。

 

全部を図に纏めるとこんな感じです。実際には作りながら適宜考えたものですから名前等がテキトーな箇所はご勘弁ください。

プログラムはモジュールとしてのfile_mng.pyを除き、全てデーモンで個別に動作させます。 

f:id:DreamerDream:20190918163220p:plain

 

各プログラムの概要一覧です。

各々のプログラムについては個別にブログに纏めることにします。

データの共用はRAMである/dev/shm/領域内を活用することにしました。

 

 

 

ファイルデータ統括モジュール

file_mng.py

今全てのプログラムから利用するファイル内容を一括で取り次いでくれるプログラム

これをimportするだけで各種ファイルの保存先から保存データを適切に拾ってくれます。
dreamerdream.hateblo.jp

 

 

 

画面表示デーモン

temp_displayd.py

素直に/dev/shm/に保存された表示用テキストをディスプレイに表示させるだけのデーモン

監視ファイルは/dev/shm/以下の

temp,time,row_0,row_1,row_2,row_3,row_4

dreamerdream.hateblo.jp

 

 

温度取得デーモン

write_tempd.py

センサー値を読むのが遅いのと℃に直すのが手間なので、画面表示と温度管理のために/dev/shm/にセンサー値を℃に直して保存するだけのデーモン

作成ファイルは

/dev/shm/temp

dreamerdream.hateblo.jp

 

 

 

スタート、ストップデーモン

start_stop_btnd.py

スタート/ストップボタンが押されたら、

ストップ時ならスタートファイルにスタート時間を記録したファイルを作る。

スタート時ならストップ処理としてスタートファイルを消す。

押された確認要にrow_0にSTAR、STOP表示

/dev/shm/にファイルを作るスタートボタン監視デーモン

監視ボタン

「スタート/ストップ」GPIO10

作成ファイルは

/dev/shm/start

/dev/shm/row_0

dreamerdream.hateblo.jp

 

 

 

温度、タイマー設定デーモン

settingd.py

/usr/local/etc/以下の設定ファイルを読み込んで画面表示/dev/shm/row_1,row_2ファイルに設定内容を書き出す。

物理ボタン操作により設定ファイルを書く

監視ボタン

「上」「下」「設定項目」ボタン

作成ファイル

/usr/local/etc/temp

/usr/loca/etc/time

/dev/shm/row_1

/dev/shm/row_2

dreamerdream.hateblo.jp

 

 

 

タイマーデーモン

timerd.py

スタートファイルを読んでタイムカウントするデーモン。

スタートファイルがある時はディスプレイ表示用timeファイルを書き換える

温度が設定温度になったらスタートファイルの日時を書き換えてスタート

設定タイムになったらstartファイルを消してrow_0を「Complete」に書き換えて終了。

監視ファイルは

/dev/shm/start

/dev/shm/temp

/usr/local/etc/set_time

/usr/local/etc/set_temp

作成ファイルは

/dev/shm/time

/dev/shm/row_0

dreamerdream.hateblo.jp

 

 

 

 

ヒーター制御デーモン

heaterd.py

startファイルが存在すれば、保存された温度ファイルに近づくようにヒーター制御を行なう。

日時を記録したログファイルを残す

監視ファイル

/usr/local/etc/temp

/dev/shm/temp

/dev/shm/start

出力

[ヒーター]

作成ファイル

ログファイル 

dreamerdream.hateblo.jp

 

 

これらデーモンは各々実行権限を与えてデーモンとして起動時に自動起動するよう設定しています。

<過去記事参考>

dreamerdream.hateblo.jp

 

実動作試験につづく↓ 

dreamerdream.hateblo.jp

 

RaspberryPiと炊飯器で低温調理器を自作してみた① 制御基盤作成

いきなりですが、低温調理器って憧れますよね?

 

 

これがあるとローストビーフにチャーシューにぃ、いろいろなことができるんです!

 

しかし、単純に63℃とか70℃とかを長時間維持するだけの機能なのに高ケーなオイ!

いや専用器具はそれなりの機能が備わっていることは解っていますよ!

けど頻繁に使わないと思われるものを買うのは躊躇します。・・・いやしかし低温調理やってみたい!

 

ってことで早速家に余って放置しているRaspberryPiで自作してみることにしました。

 

「ラズベリーパイを使って調理」って、何やらおいしそうですしね!(どーでもいい)

 

 

まずは、温度センサを取り付けます。

温度センサーは1-Wire式のものが便利です。

 

 

こいつは、以前にも室温の計測で使って便利だー!ってことで多めに買っておいたので家に在庫があります。

温度は125℃まで計測できるので問題無し!

過去記事↓で取り付けた通りなので割愛します。 

dreamerdream.hateblo.jp

 

次に、調理器具を調達します。

保温に適していて、水が蓄えられる構造の「炊飯器」や「ポット」が良さそうです。

しかし、IH式のものは制御基盤が良く解らないので、単純なヒーター式の「接続したら温まる」という単純な構造のものが良さそうです。

 

<参考記事>やはり!先輩がいらっしゃる!

www.cuspy.org

参考先の先輩はポットのAC100Vをそのままソリッドステートリレーという高価な半導体リレーを使われていますね。

 

 

 

 

僕の家には改造できるようなポットはなく、たまたま一人暮らしで使ってた3合炊きの古い炊飯器があったのでそれを使うことにしました。

炊飯器なのでコンセントに挿してすぐ過熱はしません。分解あるのみ!「もしやヒーターはリレーで直結してるのかな?」と分解してみると、ふむふむ・・・

制御信号はマイコンなので詳細不明なものの、ラッキーなことにマッキーで回路を辿っていると、基板に特にトリッキーな所は無く、高圧部回路からリレーへの解りやすい接続回路をすぐに発見しました!

f:id:DreamerDream:20190913201549p:plain

リレーの制御部には12Vの電圧がかかっていて、反対のリレー接続部をGNDへ繋げてやることでリレーが反応してヒーターに100Vが流れ過熱します。

今回はこのリレー制御部分の線だけ外に出してリレーを流用することにします。

(※家電の分解は完全に自己責任です。細かな情報を不用意に発信して、もし事故にでもなったら責任が取れませんので分解等の詳しいことは省きます。)

 

ということで、発熱体は炊飯器に元から付いているヒーターとリレーを利用します。(元から搭載されている温度ヒューズもそのまま使えるのでラッキーです!もし暴走しても安心!)

温度センサーは釜の周囲をグルッと回っていて、どうやらA/Dコンバータが必用そうなので今回はラズパイ用に冒頭の簡単接続の温度センサーを利用することにしました。

f:id:DreamerDream:20190918142350p:plain

お釜の元のセンサーのあたりに貼付けます。

 

要するに、炊飯器の構造はこんな感じだったので、

f:id:DreamerDream:20190918095455p:plain

リレーを拝借して、温度センサーを増設しただけです。

f:id:DreamerDream:20190918095509p:plain

ですので改造後も炊飯器の機能はそのまま使えます。(使う予定はありませんが)

 

 

で作ってみた制御回路がコチラです。・・・といっても上図の通りメインはフォトトランジスタと抵抗だけ(笑)あとオプションとして単品で操作できるようにプッシュスイッチ数個とディスプレイ。

 

f:id:DreamerDream:20190913202433p:plain

RaspberryPiは用途が無くなった初代のRaspberryPi A+

必要最低限の機能で低消費電力で冷却ファンも必用無いので組み込み機器には最適です。

<概要>

  • リレーの制御はフォトトランジスタで炊飯器のリレーを制御、フォトトランジスタなので炊飯器回路とは完全に安全に分離できます。
  • 温度センサーはVCC(3.3V)、GND、信号線の3線で接続しています。
  • スイッチ6個(ジャンクで取り置きしていたもので数は適当、後で何かしら機能を割り当てることにします(雑!))。
  • 有機ELディスプレイ(余っていたので)。
  • 5V線(配線しただけ、後ほど電源をUSBからではなく余ってる5V電源を基盤から接続するかも?(雑!))。

ざっくりな(優柔不断すぎる)回路というほどの回路でもありませんが、ひとまず必用な基盤は完成です。

 

あとはプログラムを書いて無事に動く事を祈るばかりです。

続く

 

 

dreamerdream.hateblo.jp

 

RaspberryPiに謎の有機ELディスプレイを接続してみた

手元に謎のディスプレイがあったので(たぶんメルカリとかで部品を買ったときのオマケ)表示させてみることにしました。

 

現物はコレ↓

f:id:DreamerDream:20190913193807p:plain

型番も何も書かれていないので・・・

「液晶、表示 Raspberrypi」と検索しても全然それらしき物がヒットしなくて困りました。唯一、端子に表示されている「VCC GND SCL SDA」という接続名は解るので仕方なくそれで画像検索してみたらヒットしましたよー!

なんと、液晶ではなく、有機EL(OLED)ディスプレイだったんですね!

 

ということで、それらしきディスプレイの表示をしておられる方のサイトを参考にセットアップしてみることにしました。

 

<参考>

Raspberry PiでI2C接続の128×64 OLEDに日本語を表示(美咲フォント) – Lifelog

 (コードはこちらから拝借しています。)

 

ディスプレイに「VCC GND SCL SDA」と表記されている通り、ラズパイの同じ端子に接続します。

注意:VCCはラズパイの3.3Vに接続しましょう!

f:id:DreamerDream:20190913194941p:plain

(※上の画像は実験中のものです。接続しただけの状態では何も変化ありません。液晶と違って有機ELはディスプレイそのものが発光するのでバックライトがありません。接続しても真っ暗のまま何も変化が無いので心配になると思いますが、接続がキチンと出来ている事を確認する術はありません。信じて進みましょう。)



 

まずは、お決まりのアップデートから

sudo apt-get update

 

ラズパイの初期設定を弄る

sudo raspi-config

 

f:id:DreamerDream:20190912155020p:plain

 「I2C」のセットアップがあるので選択して

f:id:DreamerDream:20190912155035p:plain

 再起動します。

f:id:DreamerDream:20190912155046p:plain

 

sudo reboot

 再起動後、下記のコードを入れると

sudo /usr/sbin/i2cdetect -y 1

この「3C」というのが接続したディスプレイのようです。

f:id:DreamerDream:20190912155417p:plain

LCDのアドレスは0x3c

 

sudo apt-get install build-essential python-dev python-pip

sudo pip install RPi.GPIO

sudo apt-get install git

 

これらは既にインストール済みでした。

 

 

git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git

cd Adafruit_Python_SSD1306

sudo python setup.py install

 とすると、

~~ずらずらー

//Finished processing dependencies for Adafruit-SSD1306==1.6.2//

と表示されて完了!

 

日本語フォントインストール

cd /home/pi

sudo mkdir font

sudo mkdir font/misakifont

sudo wget http://www.geocities.jp/littlimi/arc/misaki/misaki_ttf_2015-04-10.zip

(なんかエラー出てzip解凍できないから「まあ日本語表示させないしいいか」と、そのまま。)

 

公開されているコードを日本語を外して実行してみましたら、

import Image

が無いよーってことで怒られました。

ん?

pip install pillow

インストール実行しましたが、既にインストール済みとのこと

 

で、import文を

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

とすることでこれは通りました。

 

  

参考にさせていただいたサイトでは表示文字は白色でしたが、僕のは液晶の画面色がおかしい?と思い、全部塗りつぶしてみると、あら〜、上は黄色で下がブルーの2色式。

しかも上と下の間が2px程度空いているので表示場所には注意が必用なようです。

f:id:DreamerDream:20190913194357p:plain


なんだこれ?

と思ってAmazonで調べた所、どうやら↓のような2色式の商品のようです。 

なるほどー、元々そういう商品だったんですね。

 

ということで、参考コードはほぼそのままに、表示領域を探ってみました。

 

# -*- coding: utf-8 -*-

import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

import time

#ピンの出力設定24と書かれていますがこの辺よく解っていません。

RST = 24
disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

 

disp.begin()

#一度クリアーするようです

disp.clear()
disp.display()

 

width = disp.width
height = disp.height
image = Image.new('1', (width, height))

# ディスプレイ表示領域いっぱいの範囲を描画するってことですね
draw = ImageDraw.Draw(image)

# 表示領域いっぱいに四角形を色無しで描きます
draw.rectangle((0,0,width,height), outline=0, fill=0)

#タイトル テキストを設定、どの位置に書くかXY設定

title = 'TEST v2.0'
draw.text((2,0), title, fill=256)

#青字領域のテキストを設定

x=0
y = 14

for str in [ 'MyName is Onancopon' ,'hogehoge', 'hagehage', 'muninuni', 'paipai','123456789012345678901234567890']:
  draw.text((x,y), str, fill=256)
  y+=10

disp.image(image)

#実際に表示を実行
disp.display()  

 

X軸は約21文字、縦は青字が切れない所から最大で6行といったところでしょうか?

f:id:DreamerDream:20190913200527p:plain

しかしこれではあまりに詰め詰めなので実運用では10pxずつ表示させ、5行で表示させることにします。

 

※参考サイトのままの表示方法で、たぶん文字サイズとかも変更出来るのだろうけど、ひとまず表示出来たので良しとします。 

DreamerDramのブログ 1000PV/日達成しました!

いつものように、何気にPVをみていましたらー、

f:id:DreamerDream:20190912130107p:plain

 

え?え?ええ〜〜??

11日に念願の1000PV/日を達成していました!

 

f:id:DreamerDream:20190912124335p:plain

なにこれ??めちゃウレシイ!!

グラフの通り、10日からいきなりアクセス数が増えています。

 

実は今年の7月から500PV/日あたりをウロウロしていたので、気合いを入れて一ヶ月以上連続投稿してみたりもしたのですが、一向に500〜600PV台を超える気配がなかったので半ば諦めかけていました。これでやっと報われた気がします。

 

ブログPVが増えるときは一気に増えるんですねー。

これは以前にも3000PV/月のなかなか超えられない壁で体験しました。

内訳はGoogleの検索アルゴリズムの影響とかいろいろあるみたいなんですけど、本当にアクセスの変動はいきなりなんですね。

 

 

以前、2016年の7月末に100PV/日達成の記事を書いていましたから

そこから約3年もかかっています・・・長っ!

dreamerdream.hateblo.jp

 僕がんばったよー(嬉)

 

ということで、いつもご覧いただきありがとうございます!

本当にありがとうございます!

多謝!!

これからもよろしくお願い致します!

 

 

現在、ある作品を作る為にいろいろと実験をしています(チラ見せ↓)。

f:id:DreamerDream:20190913194941p:plain

また完成しましたらこちらのブログに掲載致しますのでその時は是非ご覧頂ければ幸いです。

kampa.me