本帖最后由 liuje 于 2019-2-28 22:23 编辑
*************** 2/24/2019更新 (綠板PCB, 只能用F大前版的mico.sh, 最新版的匹配度較差) **************
這兩天將小愛同學恢復出廠設置, 再重新做配置. 發現目前直接下載F大的最終版mico.sh攔截程序,
跟綠板PCB的小愛同學相容度很差. 只要連續下命令, 經常只會回應 "找不到設備....." ,
然後隔個幾十秒, 才突然動作起來.. 一整個怪異. 延遲非常嚴重 .
但只要改用底下較早的代碼, 就可以完美匹配. 請各位同鞋留意 ~
** 請修改自己的nodred服務器地址 "nodered_url=......" 此處,
還有, 如果nodered有設密碼請改這邊 nodered_auth=":" (這裡預設是無密碼)
(如有密碼請改成例如 : nodered_auth="admin:admin")
# @author FlashSoft
# == 自定义配置========================================
# 设定拦截词,以竖线分割每个拦截词,被拦截的内容会转发给nodered服务器进行处理
keywords="晚安|传感器"
# 配置nodered的接收地址
nodered_url="http://192.168.1.10:1880/miai"
# 配置从nodered更新拦截词的间隔,单位秒
# 0代表不更新,一直使用本地拦截词
# 大于0则更新,会从上面设定的nodered_url去获取拦截词,并覆盖本地的拦截词
keywords_update_timeout=0
# == /自定义配置========================================
asr_file="/tmp/mipns/mibrain/mibrain_asr.log"
res_file="/tmp/mipns/mibrain/mibrain_response.log"
nodered_auth=":"
# 解决可能存在第一次文件不存在问题
touch $res_file && touch $asr_file
res_md5=""
last_time=`date +%s`
echo "== 拦截词: $keywords"
echo "== NodeRed地址:$nodered_url"
echo "== 更新拦截词时间间隔 $keywords_update_timeout 秒"
while true;do
# 计算md5值
new_md5=`md5sum $res_file | awk '{print $1}'`
# 如果是第一次,就赋值比较用的md5
[ -z $res_md5 ] && res_md5=$new_md5
# 如果md5不等则文件变化
if [[ $new_md5 != $res_md5 ]];then
# 记录md5变化后结果
res_md5=$new_md5
# 获取asr内容
asr_content=`cat $asr_file`
# 获取res内容
res_content=`cat $res_file`
# echo $asr_content
# echo ""
# echo $res_content
# 如果拦截词不为空,且匹配到了拦截词则试图拦截
# if [ "`echo "$res_content"|grep '"domain": "smartMiot"'`" ];then
miai_domain=`echo "$res_content"|awk -F '"domain": ' '{print $2}'|awk -F '"' '{print $2}'`
echo "== 有内容更新 | type: $miai_domain"
if ([[ ! -z $keywords ]] && [[ ! -z `echo $res_content|awk 'match($0,/'$keywords'/){print 1}'` ]]) || [ "`echo "$res_content"|grep SM_NO_DEVICE_TO_OPERATE_DEVICE_LIST_NOT_EMPTY`" ];then
echo "== 试图停止"
# 若干循环,直到resume成功一次直接跳出
seq 1 200 | while read line;do
code=`ubus call mediaplayer player_play_operation {"action":"resume"}|awk -F 'code":' '{print $2}'`
if [[ "$code" -eq "0" ]];then
echo "== 停止成功"
break
fi
sleep 0
done
# 记录播放状态并暂停,方便在HA服务器处理逻辑的时候不会插播音乐,0为未播放,1为播放中,2为暂停
play_status=`ubus -t 1 call mediaplayer player_get_play_status | awk -F 'status' '{print $2}' | cut -c 5`
# echo $play_status
ubus call mediaplayer player_play_operation {"action":"pause"} > /dev/null 2>&1
# @todo:
# 转发asr和res给服务端接口,远端可以处理控制逻辑完成后返回需要播报的TTS文本
# 2秒连接超时,4秒传输超时
tts=`curl -u "$nodered_auth" –connect-timeout 2 -m 4 -s --data-urlencode "asr=$asr_content" --data-urlencode "res=$res_content" $nodered_url`
echo "== 请求完成"
# 如果远端返回内容不为空则用TTS播报之
if [[ -n "$tts" ]];then
echo "== 播报TTS | TTS内容: $tts"
ubus call mibrain text_to_speech "{"text":"$tts","save":0}" > /dev/null 2>&1
# @fixme
# 这里的4秒有点瞎扯淡,后续需要修改成判断是否TTS播报完毕
sleep 4
fi
# 如果之前音乐是播放的则接着播放
if [[ "$play_status" -eq "1" ]];then
echo "== 继续播放音乐"
# 这里延迟一秒是因为前面处理如果太快,可能引起恢复播放不成功
sleep 1
ubus call mediaplayer player_play_operation {"action":"play"} > /dev/null 2>&1
fi
fi
fi
# 以某频度去更新拦截词
if [[ "$keywords_update_timeout" -gt "0" ]];then
now=`date +%s`
step=`expr $now - $last_time`
# 根据设定时间间隔获取更新词
if [[ "$step" -gt "$keywords_update_timeout" ]];then
keywords=`curl -u "$nodered_auth" –connect-timeout 2 -m 4 -s $nodered_url`
echo "== 更新关键词 | 关键词内容: $keywords"
last_time=`date +%s`
fi
fi
sleep 0
done
复制代码
********************* 12/15更新 (以 USB-TTL 直接燒錄hex, 免安裝Arduino) ****************************
有同好問起怎麼用USB-TTL直接燒錄hex, 這邊做個簡單教程 :
1. 插上USB-TTL, 從 "設備管理器" 查詢到對應的com口, 例如我的是對應在 com5.
2. 連接好pro mini板, 共連接VCC/GND/Rx/Tx四條線, 其中 USB-TTL標示"Rx" 必須連接到 Pro mini 的"Tx"腳,
USB-TTL標示"Tx" 必須連接到 Pro mini的 "Rx"腳 (交錯連接).
3. 解壓附檔燒錄工具以及編譯好的hex代碼到某個目錄下.
4. 按住 Pro mini上的唯一一顆小按鍵(reset按鈕)不放.
5. 到剛剛解壓的目錄下, 打開 command窗口, 並運行底下命令:
avrdude -q -c stk500v1 -P com5 -b 57600 -p atmega328p -U flash:w:Xiaomi_AI_SSH_mico(181215).hex
(請自己修改 com5 這個參數, 對應到你自己的狀況)
6. 仔細看USB-TTL上的傳輸指示燈, 當看到第1次閃一下時, 立即放開Pro mini的按鍵(如果超過2秒沒放開, 可能就會失敗)
失敗的話, 如下畫面跑完後, 只要重覆以上4-5步驟, 試個2~3次肯定會成功. 成功的話, 會看到2個led燈快速交錯閃爍,
代表正開始燒錄, 整個燒錄時間大概10秒以內就完成了.
7. 燒錄完成, Pro mini會自動重啟, 會看到Pro mini上頭指示燈快速閃爍3-5秒鐘然後熄滅, 就說明能工作了.
8. 再一次提醒, 一定要找 Pro mini 5V/16MHZ的版本來燒錄 (3.3V/8MHZ串口速率無法達到115200的速率要求)
(燒錄成功 : 當USB-TTL上, 任一顆傳輸LED閃動第1下時, 閃爍時間非常短. 要在2秒內放開Pro mini上的reset按鈕, 10秒內就燒錄成功了)
(燒錄失敗 : 可能原因是沒按上面說明, 在一定時間內放開reset按鈕, 或者是Rx/Tx接錯, 都只會看到這個錯誤畫面)
(燒錄工具 + hex燒錄代碼)
avrdude-6.3-mingw32.rar
(187.15 KB, 下载次数: 186)
**********************************************************************************
********************* 12/8更新 (Pro mini 另一種代碼, 定時運行) ****************************
我改了一版pro mini程序, 變成跟F大那篇一樣, 定時10秒鐘就去檢查程序是否運行, 如沒有就運行起來..
這種方法, 可以避免以後固件大幅度升級後, 有可能輸出的文字串會不同, 原來的那種判斷特定字符串的方式有可能失效.
這種定時運行的, 就能避免此問題. 提供如下給大家參考..
#include <Arduino.h>
void setup()
{
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
for (int i=0; i<30; i++) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
delay(50);
}
digitalWrite(LED_BUILTIN, LOW);
}
void loop()
{
// 每10秒檢查 dropbear 以及 mico.sh 是否運行? 如果沒有,則打開ssh以及運行mico.sh
Serial.println();
Serial.println("test `ps|grep 'dropbear -r /data/dropbear_rsa_host_key'|grep -v grep|wc -l` -eq 0 && dropbear -r /data/dropbear_rsa_host_key");
Serial.println();
Serial.println("test `ps|grep 'sh /data/mico.sh'|grep -v grep|wc -l` -eq 0 && sh /data/mico.sh > /tmp/mico.log 2>&1 &");
delay(10000);
}
复制代码
*****************************************************************************************
********************* 11/11更新 (免拆PCB螺絲, 直接改機) ****************************
更優雅的改機方式, 可以找3pin, 1.0mm間距的排線, 直接裝上就搞定了(如下圖下方的3pin排線).
就不用拆PCB螺絲尋找背面那3個焊點了.
參考連接如: (非廣告)
*********************************************************************************
************** 11/7補充 (有朋友在問詳細一點的配線方式, 再提供圖片如下) ***********************
*********************************************************************************
****** 11/5補充 (有一些人碰到了node-red導入流程文件無法運行, 一直報錯的問題, 這邊給個提醒 *********
可能是少裝了 Node-RED 與 Homeassistant 溝通的插件.. 這部份, 幾位大佬的教程文件沒特別提到, 所以我也看一些在問, 為什麼流程文件導入後, 總是有幾個地方一直報錯, 原因就是沒有安裝插件. (我自己也是第1次用 node-red, 也是花了好幾小時才找到是插件沒裝問題)
當然, 安裝插件以後, 有幾個控制點, 包括Homeassistant佈署地址, 設備的 entity_id 等等, 也要改成你實際有的. 才會動的.
插件有兩種可選 : node-red-contrib-home-assistant-websocket 與 node-red-contrib-home-assistant .
其中 "node-red-contrib-home-assistant" 已停止維護, 只支援HA原來的密碼驗證.
而 "node-red-contrib-home-assistant-websocket" 目前還在維護中, 已支持新版HA的 token驗證.
建議安裝 node-red-contrib-home-assistant-websocket , 以免日後HA停止支持單純的密碼驗證.
可以參考這邊的安裝 : (要到node-red目錄下進行安裝才可以)
1. cd ~/.node-red
2. npm install node-red-contrib-home-assistant-websocket
https://www.npmjs.com/package/node-red-contrib-home-assistant-websocket
************************************************************************
~感謝眾多高手的努力, 讓小愛音箱在局網內就可以控制任何自製設備 ~
花了兩天時間, 終於把剛剛買的小愛音箱給改好了. 目前最新的小愛音箱都是綠色PCB,
並且通過串口連接後, 會發現 /etc/init.d 這個目錄被小米設成只讀了. 也等於斷絕了設置自動運行的可能.
"flashsoft " 大, 也有教我們使用單片機來解決這問題. (https://bbs.hassbian.com/thread-5110-1-1.html )
底下改造步驟, 簡單做個分享...
1. 按下圖把 RX/TX/GND 三個信號點焊線出來. (參考下圖)
2. 連接 USB<-->TTL , 速率設為 115200,N,8,1 . 就能直接以root身份登入 (不用輸入密碼)
輸入以下命令: (這裡, 我們修改了rsa檔的存放路徑, 因為其它文章提到的目錄, 沒法寫入,
我們改放在 /data 目錄, 就沒問題, 命令執行後, SSH就打開了)
dropbearkey -t rsa -f /data/dropbear_rsa_host_key
dropbear -r /data/dropbear_rsa_host_key
复制代码
這裡 "dropbearkey -t rsa -f /data/dropbear_rsa_host_key" 是把金鑰產生到指定的目錄下.
然後 "dropbear -r /data/dropbear_rsa_host_key" 是引用指定位置的金鑰, 執行此命令後才會真正開啟SSH.
這邊做個提醒, 如果是第1次安裝, 或者小愛同學恢復出廠設置. 需要連接串口, 至少運行一次
產生金鑰的命令. 因為單片機裡頭, 每10秒運行一次的命令, 僅僅是引用指定位置的金鑰.
所以, 全新或復歸出廠設置 這兩種狀況下, 都必須手動運行過一次 "dropbearkey -t rsa -f /data/dropbear_rsa_host_key"
否則可能會發現根本沒打開ssh. 請特別注意 !
3. 使用合適的單片機 (我是使用ATmega328P , 5V, 16MHZ的 Arduino Pro mini板) , 要注意的是,
我一開始用8MHZ / 3.3V的版本, 發現uart沒辦法跑到115200, 會變亂碼. 如果要跟我用一樣的,
請特別注意, 一定要選用5V/16MHZ版本 . 由於Pro mini體積很小, 耗電流也小(估計只有10-20mA).
其實不需用到ESP8266, 相對耗電量大很多. 取電需注意. 底下Arduino代碼供參考 :
#include <Arduino.h>
#include <SoftwareSerial.h>
SoftwareSerial swSer(10, 11);
void setup()
{
Serial.begin(115200);
swSer.begin(57600);
pinMode(LED_BUILTIN, OUTPUT);
for (int i=0; i<30; i++) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
delay(50);
}
digitalWrite(LED_BUILTIN, LOW);
}
void loop()
{
while(swSer.available())
{
String str = swSer.readString();
Serial.println(str);
}
delay(1);
}
void serialEvent()
{
while(Serial.available())
{
String str = Serial.readString();
//Serial.println(str);
swSer.println(str);
if ( (str.indexOf("Please press Enter to activate this console") > 0) or (str.indexOf("crond (busybox 1.27.2) started, log level 5") > 0) )
{
//Serial.println("Got the command!");
Serial.println();
Serial.println();
delay(10000); //一定要加上至少10秒的延遲, 如果發現, 重起之後, 本來可以, 但只回應 "沒有找到你要的設備呢......" , 可以延長到15000(15秒)
Serial.println("sh /data/mico.sh > /tmp/mico.log 2>&1 &");
Serial.println();
Serial.println("dropbear -r /data/dropbear_rsa_host_key");
Serial.println();
for (int i=0; i<30; i++) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
delay(50);
}
digitalWrite(LED_BUILTIN, LOW);
}
}
delay(1);
}
复制代码
(我的作法不太一樣, 不是用定時間隔發送, 而是偵測小愛開機時的系統運行資訊, 判斷特定字串再執行,
因此, 只會在重開機完成後運行一次. 判斷的字串就像底下這樣子.... 我是抓了兩個字串 " lease press Enter to activate this console"
以及 "crond (busybox 1.27.2) started, log level 5" 做判斷, 並且一定要延遲大約10秒, 再發送命令.
如果不做延遲馬上發送, 就只能成功打開ssh, 無法成功讓mico.sh 監控程序在背景運行起來 )
(開機時通過TTL輸出的狀態輸出片斷)
-----------(略)--------------
Starting kernel ...
uboot time: 1544270 us
domain-0 init dvfs: 4
[ 0.273594@2] ff803000.serial: clock gate not found
get key is 0x00 , curr_boot is boot1
Booting from boot1
/dev/mtdblock5 is ready now.
[ 1.609729@3] i2c i2c-1: [aml_i2c_xfer] error ret = -5 (-EIO)
[ 1.609858@3] i2c i2c-1: token 1, master_no(1) 300K addr 0x3c
Press the [f] key and hit [enter] to enter failsafe mode
Press the [1], [2], [3] or [4] key and hit [enter] to select the debug level
Please press Enter to activate this console.
[ 6.395681@0] cyttsp 0-0008: Failed to request firmware touch.cyacd
[ 6.396330@0] cyttsp 0-0008: Failed to update firmware;
[ 8.264743@3] name: mac_wifi, size 17
[ 8.280245@0] name: mac_bt, size 17
crond[1098]: crond (busybox 1.27.2) started, log level 5
复制代码
(改好的樣子, 紅框為加裝的小PCB, 使用ATmega328P , Arduino Pro mini, 小巧精幹)
4. flashsoft 大大分享的 "小爱拦截器'安装工具", 下載以後需要做修改 (因為/root , /etc/init.d 這兩個目錄,
在最新的綠版PCB, 都變成只讀了. 所以, 我們要改成其它目錄 (例如 /data) .
# @author FlashSoft
# root=`pwd`
root=""
# 脚本存放地址
#mico_path="${root}/root/mico.sh"
mico_path="${root}/data/mico.sh" ##修改為 /data
# 脚本开机启动
#mico_initpath="${root}/etc/init.d/mico_enable"
mico_initpath="${root}/data/mico_enable" ## 也修改為 /data (此檔無作用了, 因為無法成功寫入開機啟動)
mico_tmppath="/tmp"
复制代码
關於 mico.sh 此scipt ** 建議直接引用最上頭的mico.sh內容, 因為F大有改過mich.sh內容, 目前僅能適配黑版PCB .
此版本系統可能不太一樣, 已經沒有 usleep (延遲us, 微秒) 這個命令 , 如果直接運行 mico.sh 會報錯, 無法運行. 需要把 usleep xx 改成 "sleep 0" 才能保證兼容性與長期運行的可靠性.
(請參考本貼#48樓的說明 ~~~)
** 建議直接引用最上方的mico.sh內容, 因為F大在去年底有修改過mico.sh, 經過我測試, 如果現在才下載的,
跟綠色PCB相容性很差, 會有一堆延遲問題. 所以, 直接改用我上方的內容, 才能完美匹配. 02/24/2019註. **
5. 其它請參考Node-red安裝/使用, 最近幾天也有視頻操作教程. 基本上看過一遍就能明白操作原理.
(我使用的固件版本為 1.34.33 )
root@mico:/# uci -c /usr/share/mico show
uci: Entry not found
uci: Entry not found
version.version=core
version.version.ROM='1.34.33'
version.version.CHANNEL='release'
version.version.HARDWARE='S12A'
version.version.APPID='xxxxxxxxxxxxxxxxxxxx'
version.version.APPTOKEN='xxxxxxxxxxxxxxx'
version.version.UBOOT='0.0.1'
version.version.LINUX='0.0.1'
version.version.RAMFS='0.0.1'
version.version.SQAFS='0.0.1'
version.version.ROOTFS='0.0.1'
version.version.BUILDTIME='Mon, 22 Oct 2018 14:30:23 +0800'
version.version.BUILDTS='1540189823'
version.version.GTAG='commit b9e9b6640c2491c7a77a22612e47790e6c8c0356'
复制代码
最後, 祝大家都能改造成功 ~
评分
查看全部评分