2016年11月15日 星期二

RPI3's lirc

refer to : http://ozzmaker.com/how-to-control-the-gpio-on-a-raspberry-pi-with-an-ir-remote/

hardward : 1838B 接 GPIO, 3.3V, GND, PIN18

Software :
1. sudo apt-get install lirc liblircclient-dev
2. 在 /etc/modules 裏加兩行
   lirc_dev
   lirc_rpi gpio_in_pin=18
3. 改 /etc/lirc/hardware.conf
   DEVICE="/dev/lirc0"
   MODULES="lirc_rpi"
4.  reboot, 理論上應該 lircd 會自動起來, 但並沒有
5. 用mode2 測試硬體
    sudo /etc/init.d/lirc stop  ( 沒有這個也無妨, 因為 service 沒設好? )
    mode2 -d /dev/lirc0
6. irrecord --disable-namespace -d /dev/lirc0 lircd.conf
    錄試遙控器的 key, 要加 --disable-namespace 才能隨便給名字
    錄好後 copy 到 /etc/lirc/lircd.conf
7. 手動起 lircd -d /dev/lirc0 
    這是試出來的, 沒有手動起這個 irw 會說 connect fail, 
    而沒有用 -d 指定 /dev/lirc0 的話, irw 沒反應
8. 用 irw 試,  它會印 lircd.conf 出按鍵的名字
9. 原文的程式會去讀 /root/lircrc 或 /etc/lirc/lirc/lircrc 
    可以在 readconfig 那裏改 path, 但之後的 irexe 不知怎麼指定 path, 
    所以還是建了 /etc/lirc/lirc/lircrc
    那程式只是做了和 irw 類似的事
10. 設定 lircrc
    begin
        button = power
        prog   = irexec
        repeat = 1
        config = /home/pi/autoplay/starttv1.sh
    end
   起 irexe, 它就會依遙控器的 button, 去執行 config 那行


2016年7月8日 星期五

手染

黃連: 無媒染呈黃色,明礬媒染呈褐黃。染材不需多,煮開後浸十分鐘即可
檳榔:新鮮嫩果搗出汁加水煮,無媒染呈棗紅
地瓜葉:加鹽

簡單自製雲端家電

家附近的全國電子一直在播那個什麼"涼de等"的廣告, 每次去買菜都要被轟一次, 煩得很, 不過因為最近閒閒在家玩 DIY, 所以忍不住會想: 這自己做應該不難吧?

一個很簡單的設想: 1. 在外面寄e-mail回家 2.家裏的PC收到e-mail後照著信件標題的指示送個遙控訊號給冷氣機.

好像很簡單.

所以, 首先要在電腦裏存著各個家電的遙控訊號, 然後能發送它!
還是依照 mobile01 這篇文 http://www.mobile01.com/topicdetail.php?f=383&t=2845603
做出來的, 但是, 我的方法簡單多了

所需硬體 :
0. 電腦一台 (有耳機孔和麥克風孔即可, 老舊電腦應該都夠用)
1. 沒在用的音源線一條
2. 小吃店帶回來的塑膠繩一條 ( 不然縫衣線應該也可以)
3. 紅外線接收器1838B 38Khz 一顆 ( 10~30 元)
4. 5mm紅外線發射管 940nm LED 兩顆 (不到 10 元, 聽說 5mm 比 3mm 夠力, 只是聽說 )



做法 :
1. 把 音源線剪半, 剝成這樣 (紅白皮要剝掉一些, 冒出芯, 才能和 LED 連接)


2. 接收器 : 接收器外側兩支腳分別連上上圖的紅白線,  中間那支腳連上那條裸線
    發射器 : 取發射器的一支長腳和另一個的短腳連上紅線, 白線就連另外的長短腳. (注意:兩顆LED 要盡量肩并肩平行)
    從塑膠繩上撕下幾條細絲綁好,  成品長這樣 :


3. 接收器插上電腦的麥克風接頭, 發射器插進耳機孔, 硬體部份就完成了

軟體部份我寫了一支小程式 , 可以把收錄音訊直接轉為發射器可用的 wav 檔, 所以不需要像 mobile01 上那篇動用到 Audacity, 程式在此, 是個文字檔
https://gist.github.com/xvwang/5b441d1f9360b8ec067a24a04bbc904c

但要執行這個小程式需要安裝 python2.7, pyaudio 和 numpy
python2.7 下載頁 : https://www.python.org/downloads/release/python-2712/
後兩個最簡單的安裝方法是先裝 python package installer, 方法可以參考這篇 :
http://coopermaa2nd.blogspot.tw/2012/12/easyinstall-pip.html
有了pip 之後, 用 pip install pyaudio numpy 就 OK 了

軟體都裝好後, 執行
python recordSendIRWav.py
它會要你輸入按鍵名稱, 輸入一個名字按一個搖控器的鍵, (主要應該是開關鍵吧), 最好用英文, 因為我的程式沒用中文測過. 最後按 q 離開
注意, 我這程式會一直等到有錄到訊號為止, 如果按了搖控器, 它一直不出現再次要你輸入按鍵名稱的提示行, 那, 可能你的接收器失敗了....

之後會得到一堆 wav 檔, 用任一個播放器音量開到最大由耳機放播出來, 看看看被遙控的電器有沒有反應.
這裏有幾點要注意.
1. 音量先調到最大試試, 我在這點上被打敗了近一個月
2. 耳機孔的功率不大, 所以這個發射器的有效距離很有限, 我是接上音源延長線到處試, 最後決定我這個發射器的有效距離是 50~70cm (各電器不同)
3. 我在 Linux 用 mpv 可以指定由耳機孔播放, 但在 Window 上我就不知道該怎麼辦, 只好把外接喇叭 disable 掉, 才試成功的
4. 可能可以用手機播來試試, 因為手機上也有耳機孔, 但我的 Xperia J 行不通, 我看到有網友說他家三支手機只有一支可以用, 而且有效距離還只有 20 cm
5. 所以, 如果你要遙控的電器比較遠, 要嘛像我用音源延長線, 要嘛試著製作使用電池的發射器 :  http://swf.com.tw/?p=359 (有空我也會試, 成功的話再來 update)

最後就簡單了,  我寫了個小程式, 每十分鐘去檢查一下e-mail, 只要標題合規格的, 就播放一下相對的 wav.

例如 :
1. 執行 python sendIRThroughEmail.py keyword_of_today
2. 送 email 到信箱裏, 標題為 "keyword_of_today cooler_power" 開/關冷氣

注意 :
1. 這支程式裏要改成你自己的 mail-server, mail-id 和 password
2. 我用 mpv 指定由耳機播放,  在 window 上可以用 wmplayer (PATH 要設好), 但不知怎麼從耳機播...
mpv --audio-device=help 可以列出所以可用的播放硬體
3. wav 檔記得要放在執行目錄之下

sendIRThroughEmail.py 在這裏 :
https://gist.github.com/xvwang/f9e57b324085d7a3293a193e67b11643

2016年6月28日 星期二

遙控電腦的 python code

========= homeirctl.py =============================

from ctypes import *
from array import array
from struct import pack

import pyaudio
import codeset
import subprocess
import signal, sys

THRESHOLD = 2000
CHUNK_SIZE = 1024
FORMAT = pyaudio.paInt16
RATE = 38000

ERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int, c_char_p)
def py_error_handler(filename, line, function, err, fmt):
  pass

def record():
    """
    Record a word or words from the microphone and
    return the data as an array of signed shorts.

    """
    p = pyaudio.PyAudio()
    stream = p.open(format=FORMAT, channels=2, rate=RATE,
        input=True, output=True,
        frames_per_buffer=CHUNK_SIZE)

    num_silent = 0
    rcv_started = False

    r = array('h')

    while 1:
        rcv_data = array('h', stream.read(CHUNK_SIZE))
        rcv_data = [ (x>THRESHOLD) for x in rcv_data ]
        silent = (sum(rcv_data) < 10 )

        if silent and rcv_started:
          num_silent += 1
        elif not silent and not rcv_started:
          rcv_started = True

        if rcv_started :
          r.extend(rcv_data)

        if rcv_started and num_silent > 2:
          break

    stream.stop_stream()
    stream.close()
    p.terminate()
    return r

def to_bit(data) :
    sumData = []
    pN = 0
    nN = 0
    started = False
    for j in data :
      if j :
        pN = pN + 1
        if pN > 10 :
          started = True
        if nN < -10 :
          sumData.append(nN)
          nN = 0
      elif started :
        nN = nN - 1
        if pN > 10 :
          sumData.append(pN)
          pN = 0
    if pN > 10 :
      sumData.append(pN)
    if started and (nN < -10) :
      sumData.append(nN)

    result = ''
    started = False

    it =  iter(sumData)
    for x1 in it :
      try:
        x = x1 + next(it)
      except:
        break

      if x1>120 :
        result = ''
      elif x < -300 or len(result)>50:
        break
      elif x < -90:
        result = result + '1'
      else:
        result = result + '0'

    return result

def sigterm_handler(_signo, _stack_frame):
    sys.exit(0)

def main() :

  while True:
    data = record()
    signal = to_bit(data)
    try:
      buttonName = codeset.TVCODE[signal]
      print(buttonName)
    except:
      print(signal,'key not found')
    else:
      if buttonName is 'red' :
        subprocess.call("/home/viola/autoplay/starttv.sh", shell=True)
      elif buttonName is 'green' :
        subprocess.call("/home/viola/autoplay/starttvnews2.sh", shell=True)
      elif buttonName is 'yellow' :
        subprocess.call("/home/viola/autoplay/starttvnews3.sh", shell=True)
      elif buttonName is 'blue' :
        subprocess.call("/home/viola/autoplay/starttvnews1.sh", shell=True)
      elif buttonName is 'stop' :
        subprocess.call("/home/viola/autoplay/stopall.sh", shell=True)
        subprocess.call('xrandr --output VGA1 --mode 1440x900 --output HDMI1 --off', shell=True)
      elif buttonName is 'option' :
        subprocess.call("/home/viola/autoplay/startmusic.sh", shell=True)
      elif buttonName is 'soundtrack' :
        subprocess.call('xdotool search --name " - mpv" key s', shell=True)
      elif buttonName is 'soundpattern' :
        subprocess.call('xdotool search --name " - mpv" key A', shell=True)
      elif buttonName is 'speedup' :
        subprocess.call('xdotool search --name " - mpv" key Right', shell=True)
      elif buttonName is 'speeddown' :
        subprocess.call('xdotool search --name " - mpv" key Left', shell=True)
      elif buttonName is 'pauseplay' :
        subprocess.call('xdotool search --name " - mpv" key space', shell=True)
      elif buttonName is 'stepf' :
        subprocess.call('xdotool search --name " - mpv" key n', shell=True)
      elif buttonName is 'stepb' :
        subprocess.call('xdotool search --name " - mpv" key b', shell=True)
      elif buttonName is 'vup' :
        subprocess.call('xdotool search --name "playing music" key bracketright', shell=True)
      elif buttonName is 'vdown' :
        subprocess.call('xdotool search --name "playing music" key bracketleft', shell=True)
      elif buttonName is 'cursorU' :
        subprocess.call('xdotool search --name "playing music" key N', shell=True)
      elif buttonName is 'cursorD' :
        subprocess.call('xdotool search --name "playing music" key B', shell=True)
      elif buttonName is 'cursorL' :
        subprocess.call('xdotool key XF86AudioLowerVolume', shell=True)
      elif buttonName is 'cursorR' :
        subprocess.call('xdotool key XF86AudioRaiseVolume', shell=True)
      elif buttonName is 'mute' :
        subprocess.call('xdotool key XF86AudioMute', shell=True)
      elif buttonName is 'epg' :
        subprocess.call('chromium-browser --app="http://hichannel.hinet.net/radio/mobile/index.do?id=205#"', shell=True)
      elif buttonName is '3D' :
        subprocess.call("/home/viola/autoplay/startplaying.sh", shell=True)
      elif buttonName is 'information' :
        subprocess.call('xdotool search --name " - mpv" key t', shell=True)
      elif len(buttonName)==1 :
        subprocess.call('xdotool search --name " - mpv" key '+buttonName, shell=True)

if __name__ == '__main__':
  signal.signal(signal.SIGTERM, sigterm_handler)
  signal.signal(signal.SIGINT, sigterm_handler)

  c_error_handler = ERROR_HANDLER_FUNC(py_error_handler)
  asound = cdll.LoadLibrary('libasound.so')
  asound.snd_lib_error_set_handler(c_error_handler)

  main()

========== codeset.py ====================
TVCODE = {
'111111110001000000001110':'red',
'111111011101000000100010':'green',
'111111000111000000111000':'yellow',
'111111100111000000011000':'blue',
'111111111010000000000101':'pauseplay',
'111111101110000000010001':'speedup',
'111111010110000000101001':'speeddown',
'111111100011000000011100':'stop',
'101101110010010100001101':'stepf',
'101101010010010100101101':'stepb',
'111111010010000000101101':'option',
'111111011000000000100111':'vup',
'111111111000000000000111':'vdown',
'111111100000000000011111':'power',
'111111000110000000111001':'soundtrack',
'111111100110000000011001':'soundpattern',
'111111101000000000010111':'mute',
'111111110000000000001111':'information',
'111111010111000000101000':'epg',
'111111011001000000100110':'return',
'111111100101000000011010':'OK',
'101101101110010100010001':'3D',
'111111101101000000010010':'cursorR',
'111111001101000000110010':'cursorL',
'111111110101000000001010':'cursorU',
'111111010101000000101010':'cursorD',
'111111000100000000111011':'1',
'111111100100000000011011':'2',
'111111100100000000011011':'3',
'111111010100000000101011':'4',
'111111000100000000111011':'1',
'111111100100000000011011':'2',
'111111010100000000101011':'3',
'111111110100000000001011':'4',
'111111001100000000110011':'5',
'111111101100000000010011':'6',
'111111011100000000100011':'7',
'111111111100000000000011':'8',
'111111000010000000111101':'9',
'111111100010000000011101':'0' }

============= recordWavToFile.py =====================
import pyaudio
import wave
import numpy
from array import array

FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 38000
CHUNK = 1024
RECORD_SECONDS = 2
WAVE_OUTPUT_FILENAME = "file.wav"

audio = pyaudio.PyAudio()

# start Recording
stream = audio.open(format=FORMAT, channels=CHANNELS,
                rate=RATE, input=True,
                frames_per_buffer=CHUNK)
print "recording..."
frames = []

for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
    data = stream.read(CHUNK)
    frames.append(data)
print "finished recording"


# stop Recording
stream.stop_stream()
stream.close()
audio.terminate()

waveFile = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
waveFile.setnchannels(CHANNELS)
waveFile.setsampwidth(audio.get_sample_size(FORMAT))
waveFile.setframerate(RATE)
waveFile.writeframes(b''.join(frames))
waveFile.close()

================ drawWavPlot.py ====================
from scipy.io import wavfile
from matplotlib import pyplot as plt
import numpy as np

# Load the data and calculate the time of each sample
samplerate, data = wavfile.read('file.wav')
print data
times = np.arange(len(data))/float(samplerate)

# Make the plot
# You can tweak the figsize (width, height) in inches
plt.figure(figsize=(20, 4))
plt.fill_between(times, data[:,0], data[:,1])
plt.xlim(times[0], times[-1])
plt.xlabel('time (s)')
plt.ylabel('amplitude')
#You can set the format by changing the extension
#like .pdf, .svg, .eps
plt.savefig('plot.png', dpi=100)
plt.show()

DIY 用電視遙控器控制電腦

簡單說, 要DIY的硬體就長這樣 :


左邊是音源線的接頭--舊音源線剪下來剝了外皮的, 右邊是一顆紅外線接收器 VS1838B. (別的紅外線接收器能不能用我不知道, 我也是在網路上看來的, 然後去電子材料行說要買紅外線接收器, 店員拿了三顆給我看, 我挑出和網路上(看得懂的)照片一樣的那一顆.

然後根據下面這張網路找來的圖, 把三支腳連接好
(圖是 google 來的, 沒有記下出處, 原圖主人有意見的話, 我立刻處理!)


圖裏是用三根塑膠繩分出來細絲綁的(就去買小吃時綁塑膠袋的那種繩子), 至於為什麼是這種繩子, 不為什麼, 之前是用膠帶黏的, 掉了兩次, 第三次修理時剛買了晚餐回來, 順手用上, 結果效果很好!

做好之後, 就插入電腦的麥克風接口.

開啟錄音軟體, 拿著電視遙控器對它按幾下, 能收到音的話, 這硬體就算成功了.

然後, 需要能解析變成音訊的紅外線訊號的程式, mobile01 上有人分享過 windows 上的作法, 但我家電腦是 ubuntu, 不合用.
又找了幾種做法, 都試不出來, 然後我才想到, 我不需要'正確的'解析訊號, 我只要能分辨出各個按鍵的不同就好了啊! 我自己就是 programmer, 雖然行業不同, 但應該不難吧!

1. 先把錄下的音訊畫出波型, 看有沒有什麼特徵
   -> 這個 google 到一支 python 小程式. 很快就畫出來, 然後, 果然有特徵.
2. 找個能讀音訊檔的程式, ---> 其實和上面那支同出一源
    雖然我的 python 功力就只有幼稚園級, 但好在有 google, 一個假日, 完成!
3. 聲寶電視遙控器上有一堆平常用不到的鍵, 例如一排紅黃藍綠, 好像是給外接 USB 用的, 我沒接, 所以就拿來用啦, 如藍鍵就是看東森網路新聞 :
mpv --audio-device='alsa/hdmi:CARD=Intel,DEV=0' -fs -geometry 1400:0 --ytdl-format=95 "https://www.youtube.com/watch?v=jMN4cxyhJjk"
( 我的電腦接雙銀幕, 電視定義為右邊那個, 所以用 geometry 1400:0 送到電視上去看)
4. 完成, 現在用一個電視遙控器, 就可以開電視, '轉'到東森新聞/Skynew/日本網路新聞, 好像真的有第四台似的...