黒電話インタフェースを制作 (ラズパイに繋げられるように)してみた
1. はじめに
今ではあまり見かけなくなった黒電話。通称600型電話機。
昭和育ちの我々にとってこれこそが The電話なのですよね。
どの家庭にも必ずあったものです。
- 電話はダイヤルを回してカチカチ音を聞きながらかけるもの!!!
- 大きいベルでリンリンなってこそなんぼの呼び出しベル!!!
絶対的存在感もありました。
最近すっかり見なくなりましたが、ジャンク屋やオークション、メルカリ等で入手できます。
黒電話と検索すると色々出てきますし、値段によっては出たらあっという間に売り切れる人気ぶり?
- 入手したら動かしたくなりますよね!
↓ - どうせなら通話もしたくなりますよね!
↓ - 通話ができるようになると、専用電話番号が欲しくなりますよね!
↓ - 専用電話番号ができたら、今度は持ち歩きたくなりますよね!
それが当然の流れです!!!
というわけで、以下の欲求を満たすべく黒電話をハックしてみました。
- ダイヤルを回して電話したい。
- 馴染みのあるベルの音で着信したい。
- 黒電話を持ち運んで携帯として使いたい。
- 黒電話側は差し替えて使えるようにしたいので、魔改造は行わない。(他にもコレクションが増えそうなので繋ぎ変えたい)
2.ハード制作
2-1. 実現方法の検討
欲求を満たすためには SIPフォン等のIP電話サービスと連携するのがよさそうです。それにはまずネットにつながるようにしなければいけません。
なんだか、IoTっぽくなってきました…
しかしながら、携帯できるようにするには小型のPCが要ります。
ネット環境や各種サービス、そのためのプラットフォーム環境も含め、十分揃っていて携帯できるほど小型でとなると、ラズパイを使うのがよさげです。
2-2. 最初の課題
ラズパイを使うというところで、まず初めに問題となる点は、電話機とラズパイは、ハードウェアインタフェースをどうするかというところです。
そもそも、黒電話は2本線でつながっているだけで電源もありません。
欲しいのは
- 音声入力インタフェース
- 音声出力インタフェース
- ダイヤルパルス信号インターフェス
- ベル音インターフェース
- 電源
黒電話は、これらのすべての信号を2本線で賄っています。
すごい発明だとは思います。しかし、ラズパイと接続するためには、この2本線から上記信号を分離してを取り出す必要があります。
色々と調査してこんなものを見つけました。
これは、2台のアナログ電話をつないで、片方の受話器を持ち上げると他方のベルが鳴りだして、取ると通話ができるというインターフォン(内線通話)の様な機能を持ちます。
疑似交換機とあるので、回線繋ぎ変え機能まであるように見えますが、通話は1対1なので繋ぎ変える機能はありません。必然的にダイヤルする必要もないためその機能はありません。
ハード的に交換機の様につながっている様な挙動をするという意味っぽいです。
欲しい機能で不足しているのは、
- 音声入力インタフェース
- 音声出力インタフェース
- ダイヤルパルス信号インターフェス
音声入出力については、何処かで小型電話のジャンクを見つけてきてばらし、スピーカーとマイクを取っ払って、配線に直接つなげば何とかなります。
ダイヤルパルス信号も最悪はカチカチ音を機械学習させて音声認識で回数数えれば何とかなるかもとも思っていました。(結局この方法は不要でしたが…)
というわけで、この疑似交換機をベースに改造することに決定しました。
購入の決め手になったのは以下の3点です。
- 回路図が公開されていてシンプルで、解析・改造しやすそうなところ。
- 見た回路図がシンプルで理解しやすそうだったこと。
- 制御は PICマイコンで 5V電源系の Arduinoに簡単に置き換える事ができそうなこと
なお、本記事作成に当たって、本キットの開発製造元である (有)トライステート様 に、以下の条件の基回路図の使用や改造した物を使っての記事の投稿について許諾頂いています。もし、記事を見て参考に制作等される場合はご留意ください。
許諾条件:
- トライステート製の「PIC疑似電話交換機キット」を使用した旨。
- 改造で起こった諸問題は、自己責任である旨。
2-3. 回路解析
回路図を見ると、ほぼ端子につながったリレー回路と、フォトカプラーから入力された信号の端子入力回路です。
一部オーディオ系のアンプICにつながった部分もありますが、あまり複雑な制御ではなさそうです。
制御は PICマイコンで行われています。ソフトの中身は見えないのでブラックボックスですが、リレー制御とベル鳴動の動作程度なら外から解析して、同じ動作をさせてやれば動作すると考えました。こんな感じで
回路を読み解いていくと、入ってきた信号に対してつながったを検知し、リレーを切り替えるだけの単純な回路という事が予想付きます
アナログのオーディオ信号も、呼び出し時に呼び出し側に流れている 400Hz のトーン音を出しているのと、呼び出しベルを駆動するための 16Hz の矩形波が出ているだけであろうとの予想です。
2-4. 端子ハッキング
回路の解析結果を裏付けるために、 解析用に簡易オシロ+簡易ロジアナを作成し信号を解析しました。
Arduinoにて下の画像の通り各端子の状態を読み取れるような様な治具を作り、
PICマイコンとICソケットの間に挟み込んで、各端子の信号の状態を読み取り Arduino のシリアルに出力します。
それをさらに、Arduino のシリアルプロッタでグラフに出力すると、こんな感じの簡易測定器になります。
リレーの制御は超低速ですし、アナログ信号は周波数まで図る必要がないので、最速で回せば十分な感じです。というより、アナログ信号は図の通り速度が足りずに波形がつぶれてしまうので、別途オシロをつないで計測しました。
音声回路とベル駆動につながっている2端子はアナログ端子として analogRead() で読み取ります。
リレーの駆動回路やフォトカプラにつながっている回路は、High/Low 信号だけのはずなのでデジタル入力端子として digitalRead() で読み取ります。
そして、読み取った値にオフセット付けたり map() 関数でスケーリングしたりして、各チャンネルが重ならない様なグラフとして読み出しやすい値に変換して、Serial.print でシリアルに出力します。
こんな感じです。
Arduino_BlackTEL_Hack.ino
int DigitalData[6];
int AnalogData[2];
char buf[240];
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(4, INPUT);
pinMode(5, INPUT);
pinMode(6, INPUT);
pinMode(7, INPUT);
}
void loop() {
// put your main code here, to run repeatedly:
int MappedAnalogData[2];
DigitalData[0] = digitalRead(2);
DigitalData[1] = digitalRead(3);
DigitalData[2] = digitalRead(4);
DigitalData[3] = digitalRead(5);
DigitalData[4] = digitalRead(6);
DigitalData[5] = digitalRead(7);
AnalogData[0] = analogRead(0);
AnalogData[1] = analogRead(1);
MappedAnalogData[0] = map(AnalogData[0], 0, 1023, 700, 780);
MappedAnalogData[1] = map(AnalogData[1], 0, 1023, 600, 680);
sprintf(buf, "%d, %d, %d, %d, %d, %d, %d, %d",
MappedAnalogData[0], MappedAnalogData[1],
((DigitalData[0] == LOW)? 500: 580),
((DigitalData[1] == LOW)? 400: 480),
((DigitalData[2] == LOW)? 300: 380),
((DigitalData[3] == LOW)? 200: 280),
((DigitalData[4] == LOW)? 100: 180),
((DigitalData[5] == LOW)? 0: 80)
);
Serial.println(buf);
delay(5);
}
将来的にもリレーの動作状況が分かりやすくなると思ったので、74LCX245 バッファを介して各端子の H/L がわかる LED も付けました。
基本的に予想通りの挙動となりました。以下の画像の様に、解析結果とアナログ端子のオシロ波形画面、電話を同時に画面に映して録画することで、どういう操作をしたときにどういう波形になるかを細かく記録し、動画再生・停止・スローを駆使して解析しました。
以下は、左側の緑色電話から発呼した場合の一連の信号解析結果です。
信号の中身をまとめると、
[アナログ側]
- (出力)トーン音 (400Hz)
- (出力)ベル鳴動用パルス (16Hz)
[デジタル側]
- (出力)回路反転リレー信号
- (出力)ベル鳴動リレー信号
- (入力)相手の回路反転検知信号
デジタル側は接続電話2チャンネル分で6端子になります。
受話器を持ち上げると、「回路反転リレー信号」が ON になり、その状態が「相手側の回路反転検知信号」として反映され受話器が持ち上げられたことが認識できる仕組みです。
アナログ側はのトーンオンは400Hz のツー音に使用されます。他にも終話音"ツー>無音>ツー>無音" の1秒おきの繰り返し等の信号も出力されている様です。
アナログ側の「ベル鳴動パルス」は 16Hz の低い周波数の方形波を出力し、疑似交換機回路で電圧が 5V->15Vに昇圧され、それが相手のベルを叩くことになります。(16Hz という周波数でベルを1秒間に16回ならしているわけですね。)
あともう一つオリジナルの疑似交換機にはない機能である、ダイヤル時の挙動も確認します。
ダイヤルを回してみて、どのような波形が出るのかを、同様にグラフで確認します。フォトカプラーにつながった「相手の回路反転検知」端子の所にパルス信号が出てきました。これの High/Low の方形波の山の数を数えることで、何番をダイヤルしたか判別可能なことがわかります。
というわけで、ブラックボックスであるソフト制御の内容が理解できました。
2-5. 音声分離回路
さて、回線制御部分は解明したわけですが、音声信号をラズパイに入出力してやる必要があります。
前に、「音声入出力については、何処かで小型電話のジャンクを見つけてきてばらし、スピーカーとマイクを取っ払って、配線に直接つなげば何とかなります。」
とは書きましたが、大型化してしまうので何とかしたいところです。
2本線から、スピーカーとマイクの2つの信号を取り出す必要があります。
調べていくと、スピーカーとマイクで別々のオフセットがついた(中心電圧が違う)信号なのでそれを分離してやるようなものと理解しました。
色々と試行錯誤したのですが、組み入れてしまって最終的にどういう回路になったかが判らなくなってしまったのと、まだ若干マイクの音がスピーカーに混じるのでもう少しチューニングが必要です。そのため、現時点では回路図は載せません。
ですが、スピーカー側には直列にグランド側に抵抗を、マイク側には直列に信号側に抵抗を入れて、アンプを通してといったような内容の回路です。
チューニング完了してから回路含めて更新しようかと考えています。
とりあえず、混じってはいても会話ができるレベルにはなりました。
3. ソフト制作
3-1. Arduinoで PICと同等等の制御ソフト
次は、解析結果をもとにはずは、改造前の疑似交換機についていた PICマイコンの制御ソフトと、同等のものをArduinoで作ってみました。
- 発呼側が受話器を上げると、ベル用のリレーを操作して相手のベルを鳴らしだす。
- 相手が受話器を取ると回路が反転される。と同時にフォトカプラに受話器を上げたという信号が伝わる。
- 両方の受話器が上がったことにより、ハード的にリレーが切り替わり、音声信号のラインがつながる。
- 通話を開始する
という流れです。
この制御プログラムを Arduinoで真似してやることで、見事に同じ挙動が実現できました。
そして、疑似交換機には無い機能であるダイアリングの仕組みを組み入れました。
予想通りにパルスで入ってくる方形波の数を数えるだけでした。実際パルス数を数える様な制御をソフトに組み込んでみてシリアルログに出力し、ちゃんと番号が認識できることを確認しました。
3-2. Arduinoで制御ソフト
どう制御すればいいのかがわかってきたので、次は実際の交換機動作となります。
ラズパイをモデムのように見立てて制御ができると、簡単にインターフェースとして動作させられると考えました。
そこで、ラズパイとのインタフェースは、よくあるモデムコマンドを流用した自己カスタムな(というよりまんまかも)ATコマンドを使用するようにしました。
こんな感じです。
ATコマンド | 動作 |
---|---|
AT<CR><LF> | 待ち受けに戻す |
ATDPxxxxxx<CR><LF> | xxxxxxにダイヤルする |
ATA<CR><LF> | 着信に応答する |
ATH<CR><LF> | 切断する |
応答コード | 意味 |
---|---|
<CR><LF>OK<CR><LF> | OK応答 |
<CR><LF>ERROR<CR><LF> | エラー応答 |
<CR><LF>CONNECT<CR><LF> | 接続完了 |
<CR><LF>RING<CR><LF> | 着信あり |
<CR><LF>BUSY<CR><LF> | 話し中 |
<CR><LF>NO CARRIER<CR><LF> | 切断された |
異常系やキャンセル動作を考えるとちょっと複雑な状態遷移になるので、そのあたりを設計し
主に以下の機能を実装します。
3-2-1. 発呼動作
- 待ち受け中に受話器を持ち上げると、ツーというトーン音を鳴らすとともに、ダイヤル待ちに入る。
- ダイヤルするとパルス数を数えて、ダイヤル番号を1桁ずつ確定させる。
ツー音はダイヤル開始した時点で停止する。
0.5sec 以下の間隔のパルス数を数え、それ以上の間隔は桁の区切りとする。
5秒以上の間隔になった場合、呼び出し番号の確定とする。 - 番号が確定すると、ATコマンドにてダイヤルコマンド (ATDPxxx)を送信する
- 応答コードで 接続 (CONNECT)が帰ってきたら、リレーを切り替え通話状態にする。
- 通話状態の時に受話器を置くと、リレーをもとに戻して、回線を切断するとともに、ATコマンドにて切断コマンド (ATH) を送信する。
- 通話状態の時に 応答コードで切断 (NO CARRIER) が届いたら、リレーをもとに戻して、回線を切断する。
- 切断が確認されたら AT コマンドで、待ち受けに戻す (AT) コマンドを送信する。
3-2-1. 着呼動作
- 待ち受け中に ATコマンドの応答コードで 着信あり (RING)が来たら、ベルを鳴らし始める。
- ベルが鳴っているときに、受話器を取ったらベルを止め ATコマンドにて、着信応答 (ATA)コマンドを送信する。
- リレーを切り替え通話状態にする。
- 通話状態の時に受話器を置くと、リレーをもとに戻して、回線を切断するとともに、ATコマンドにて切断コマンド (ATH) を送信する。
- 通話状態の時に 応答コードで切断 (NO CARRIER) が届いたら、リレーをもとに戻して、回線を切断する。
- 切断が確認されたら AT コマンドで、待ち受けに戻す (AT) コマンドを送信する。
3-3. 音声疎通確認
回線の制御は出来ましたが、通話を実現するには音声の入出力も重要です。
次には、送話器からの音声をラズパイに録音、ラズパイからの音声を受話器で再生できるかを確認します。
スピーカー側テスト
ラズパイからサイン波を再生してやり、黒電話受話器のスピーカーから聞こえることを確認します。
speaker-test -t sine -f 400
いい感じです。
マイク側テスト
arecord -f cd test.wav
で黒電話受話器のマイクから、よくあるセリフ
「もしもし、ただいまマイクのテスト中」
で録音してやり。
aplay test.wav
それを、再生して黒電話受話器のスピーカーから聞こえることを確認。
ノイズが多いのと自分の声がエコーの様に聞こえてしまいますが、回路のチューニングには時間が掛かりそうなので、ひとまずこれでOKとしました。
3-4. 動作確認用対抗ソフト
動作確認用に、ラズパイでArduinoと会話のお相手をするソフトを python で作成しました。
こんな感じのもので、 Arduino から ATコマンドを受けたらログを吐き出しつつ、応答コードを返す、そして通話中は受話器で話した声を録音し、エコーバックする様なソフトです。
これを使うことで、ATコマンドの応答コードを伴う状態遷移が Arduino 側で動くことが検証でき、さらに音声の入出力についてもテストすることができるようになります。
-
CALL<Enter> と打つとATコマンド応答コードの 着信あり(RING) を送信して、黒電話を着信状態にします。
-
その後黒電話の受話器が取られて、ATコマンドの着信応答 (ATA) を受信すると、 OK を返し、Arduino側を通話状態にします。
-
通話状態になったら、送話器からの音声を3秒間録音します。
-
3秒たったら再生に切り替え、録音された音声を受話器に流します。以降録音と再生を繰り返します。
-
受話器が置かれて、ATコマンドの切断 (ATH) を受信したら、OKを返し、Arduino 側で切断処理を実行させて、待ち受けに戻します。
-
Arduino側が待ち受けに戻って ATコマンドの待ち受け(AT) を受信すると、OKを返します。
-
EXIT<Enter> と打つと終了します。
改造した部分でもなくなんの柵もないのと、大したことやっていないのでソースも公開します。
こんな感じです。
BlkPhoneAnswTest.py
import time
import threading as th
import serial
import datetime
import SimpleQueue
import pyaudio
import wave
CHUNK_SIZE = 1024
AnsweringCount = 7 - 1
TalkingTimeout = 30.0
RecPlayToggleInterval = 3.0
SerialRecvTimeout = 0.2
is_active = True
ring_count = 0
is_playing = False
is_recording = False
is_talking = False
is_serial_ready = False
is_queue_ready = False
def key_watch():
global in_str
global is_active
global is_calling
in_str = input().upper()
is_calling = False
while (in_str != 'QUIT' and in_str != 'Q' and in_str != 'EXIT' and in_str != ''):
if ( ( is_calling == False) and (in_str == 'CALL' or in_str == 'C') ):
is_calling = True
ser.write(b'\r\nRING\r\n')
print(timestamp()+"[PYTHON3]$>RING")
in_str = input().upper()
is_active = False
def initialize_serial():
global ser
global is_talking
global is_calling
global is_serial_ready
print("[Black-TEL python answering Test] Ver. 0.04")
ser = serial.Serial('/dev/ttyACM0', 115200, timeout = 0)
is_talking = False
is_calling = False
print(timestamp()+"[PYTHON3]$Serial Ready!")
is_serial_ready = True
def thread_read_serial():
global que
global ser
global is_active
global is_serial_ready
global is_queue_ready
que = SimpleQueue.SimpleQueue(1024)
is_queue_ready = True
print("thread_read_serial Started!")
while ((is_serial_ready == True) and (is_active == True)):
data = ser.read(1)
if ( len(data) != 0 ):
que.Put(data)
#print(data, len(data))
print("thread_read_serial Ended!")
def read_line_serial():
global que
global is_active
global is_queue_ready
#line = ser.readline()
timeout_time = time.time() + SerialRecvTimeout
ret_found = False
line = b''
while ((is_queue_ready == True) and (is_active == True) and (ret_found == False)):
if (que.DataExists() == True):
timeout_time = time.time() + SerialRecvTimeout
ret, data = que.Get()
if (ret == True):
line += data
if (data == b'\n'):
ret_found = True
else :
print("$BufferOverRun")
else :
if ( (line == b'') and ( timeout_time < time.time() ) ):
break;
return line
def loop_serial():
global is_talking
global is_calling
global is_recording
global is_playing
global ring_count
global disconnect_time
global toggle_time
line = read_line_serial()
utf8_line = line.decode(encoding='utf8',errors='replace').replace('\n','').replace('\r','')
if (line != b''):
if (line == b'AT\r\n'):
print(timestamp()+"[PYTHON3]$<" + utf8_line)
ser.write(b'\r\nOK\r\n')
print(timestamp()+"[PYTHON3]$>OK")
elif (line == b'ATA\r\n'):
disconnect_time = time.time() + TalkingTimeout
start_recording()
is_talking = True
is_calling = False
ring_count = 0
print(timestamp()+"[PYTHON3]$<" + utf8_line)
ser.write(b'\r\nOK\r\n')
print(timestamp()+"[PYTHON3]$>OK")
elif (line == b'ATH\r\n'):
finish_audio()
is_talking = False
is_calling = False
print(timestamp()+"[PYTHON3]$<" + utf8_line)
ser.write(b'\r\nOK\r\n')
print(timestamp()+"[PYTHON3]$>OK")
elif ( ( len(utf8_line) >= 4) and (utf8_line[0:4] == 'ATDP')):
call_number = utf8_line.replace('ATDP', '' )
print(timestamp()+"[PYTHON3]$<" + utf8_line)
print(timestamp()+"[PYTHON3]$DIALING>>" + call_number)
ser.write(b'\r\nOK\r\n')
print(timestamp()+"[PYTHON3]$>OK")
elif ( ( len(utf8_line) >= 11) and (utf8_line[0:11] == '|Bell = OFF') and (is_calling == False) ):
if ( ring_count < AnsweringCount ):
ring_count += 1
else :
ser.write(b'\r\nCONNECT\r\n')
print (timestamp()+"[PYTHON3]$>CONNECT")
disconnect_time = time.time() + TalkingTimeout
is_talking = True
is_calling = False
ring_count = 0
else:
print(timestamp()+"[ARDUINO]" + utf8_line)
if (is_talking == True):
if ( disconnect_time < time.time() ):
finish_audio()
ser.write(b'\r\nNO CARRIER\r\n')
is_talking = False
is_calling = False
print(timestamp()+"[PYTHON3]$>NO CARRIER")
else :
if (toggle_time < time.time()) :
if (is_playing == True) :
stop_playing()
start_recording()
elif (is_recording == True) :
stop_recording()
start_playing()
def finalize_serial():
global is_serial_ready
is_serial_ready = False
ser.close()
print("Serial Closed!")
def timestamp():
timestr = (datetime.datetime.now().strftime('%m%d%H%M%S.%f'))
return timestr
def start_recording():
global is_recording
global toggle_time
global rec_stream
global wav_file
toggle_time = time.time() + RecPlayToggleInterval
is_recording = True
print(timestamp()+"[PYTHON3]$Start REC. ()")
wav_file = wave.open("./test.wav", "wb")
wav_file.setnchannels(1)
wav_file.setsampwidth(aud.get_sample_size(pyaudio.paInt16))
wav_file.setframerate(11050)
rec_stream = aud.open(format = pyaudio.paInt16, channels=1, rate=11050, input = True, frames_per_buffer = CHUNK_SIZE, stream_callback= recording_callback)
rec_stream.start_stream()
def recording_callback(in_data, frame_count, time_info, status) :
global wav_file
wav_file.writeframes(in_data)
return in_data, pyaudio.paContinue
def stop_recording():
global is_recording
global rec_stream
global wav_file
rec_stream.stop_stream()
rec_stream.close()
wav_file.close()
is_recording = False
print(timestamp()+"[PYTHON3]$Stop REC. []")
def start_playing():
global is_playing
global toggle_time
global play_stream
global wav_file
toggle_time = time.time() + RecPlayToggleInterval
is_playing = True
print(timestamp()+"[PYTHON3]$Start PLAY. |>")
wav_file = wave.open("./test.wav", "rb")
#wav_file.setnchannels(1)
#wav_file.setsampwidth(aud.get_sample_size(pyaudio.paInt16))
#wav_file.setframerate(11050)
play_stream = aud.open(format = pyaudio.paInt16, channels=1, rate=11050, output = True, stream_callback= playing_callback)
play_stream.start_stream()
def playing_callback(in_data, frame_count, time_info, status):
global wav_file
data = wav_file.readframes(frame_count)
return (data, pyaudio.paContinue)
def stop_playing():
global is_playing
global play_stream
global wav_file
play_stream.stop_stream()
play_stream.close()
wav_file.close()
is_playing = False
print(timestamp()+"[PYTHON3]$Stop PLAY. []")
def finish_audio():
if (is_playing == True) :
stop_playing()
if (is_recording == True) :
stop_recording()
def main_process():
global aud
aud = pyaudio.PyAudio()
th.Thread(target = key_watch, args = (), name = 'key_watch', daemon = True).start()
ser = initialize_serial()
th.Thread(target = thread_read_serial, args = (), name = 'read_serial', daemon = True).start()
while is_active:
loop_serial()
finalize_serial()
aud.terminate()
main_process()```
```python:SimpleQueue.py
class SimpleQueue:
def __init__(self, _size):
self._Size = _size
self._DataBuffer = [0] * (self._Size+1)
self.Clear()
print("Queue size of " + str(self._Size) + " ready")
def Clear(self):
self._PutPos = 0
self._GetPos = 0
def Put(self,data):
if (self._PutPos < self._Size):
NextPos = self._PutPos + 1
else:
NextPos = 0
if (NextPos == self._GetPos):
return False
else:
self._DataBuffer[self._PutPos] = data
self._PutPos = NextPos
return True
def Get(self):
if (self._GetPos == self._PutPos):
#print(f"No data for GET{self._PutPos},{self._GetPos}")
return False
if (self._GetPos < self._Size):
NextPos = self._GetPos + 1
else:
NextPos = 0
data = self._DataBuffer[self._GetPos]#.encode()
self._GetPos = NextPos
return True, data
def DataExists(self):
if (self._GetPos == self._PutPos):
return False
else :
return True
最後に、以上の解析からテストまでの様子を動画にまとめたものを
@デモ動画に
として掲載します。
4. まとめ
ハックから始まってガチな回路制作まで経て、何とかラズパイと黒電話機のインターフェースを作成することができました。
システム構成図的にはこのようになります。
ラズパイとインターフェースができてしまえば、あとは IPフォンと連携するだの、電話会議システムと連携するだの、Twilio 等の電話サービスと連携するだのすれば、電話として使うことができるだの、いろいろと応用がききそうです。
5. 参考
外部サイトに記載した記事やコンテスト挑戦等の参考情報について記載します。
5-1. Twilioオンラインコンテスト2021
Twilio オンラインコンテスト2021 が開催されていたので、Twilio との連携に挑戦しました。そちらの記事も公開します。
コンテストの規定により、記事は別サイト Protopedia での掲載となります。
コンテスト記事:
8月分作品紹介にて紹介されました。有りがたいことに、8月月間賞を頂きました
審査動画:
5-2. みんなのラズパイコンテスト2021
記事を見た知人の勧めなどもあり みんなのラズパイコンテスト2021 に挑戦することにしました。Twilio との連携の部分を含めて、黒電話を携帯できるようになるところまでに範囲を広げ、全体的に見直しをかけ応募しました。
現在審査待ち状況です。
投稿者の人気記事
-
TakSan0
さんが
2021/08/27
に
編集
をしました。
(メッセージ: 初版)
-
TakSan0
さんが
2021/08/28
に
編集
をしました。
(メッセージ: (有)トライステート様許諾に伴い修正)
-
TakSan0
さんが
2021/08/31
に
編集
をしました。
(メッセージ: 公開用に編集+動画追加)
-
TakSan0
さんが
2021/08/31
に
編集
をしました。
(メッセージ: タグの付け忘れ修正。)
-
TakSan0
さんが
2021/08/31
に
編集
をしました。
(メッセージ: Twilioコンテスト応募完了に伴う変更)
-
TakSan0
さんが
2021/10/09
に
編集
をしました。
(メッセージ: 図等をわかりやすいものに差し替え。)
-
TakSan0
さんが
2022/01/05
に
編集
をしました。
(メッセージ: ライセンス設定等更新)
ログインしてコメントを投稿する