用NodeJS驅動硬件。node
心塞塞的,device被佔用了,只能叫onedevice了。這感受。。。。。。🙄git
這是一個旨在用NodeJS驅動硬件的驅動包。開箱即用、完善的文檔、持續更新、友好的API。用樹莓派打造本身的智能家居。github
我對智能家居很是感興趣,並一直想要本身定製化diy,用智能化設備控制家裏的一切設備。因此有了這個,是我一直在用的,我會持續的集成更多型號的硬件驅動和傳感器,和更多抽象的接口。算法
DIY,個性化,定製化,徹底可控是oneDevice的核心。express
GitHub地址npm
v0.0.2 @ 2018-04-22 17:19canvas
test文件夾下面有測試例子,這些都在個人Linux raspberrypi 4.4.34-v7+ Raspbian GNU/Linux 8.0 (jessie)
下面測試經過。瀏覽器
0. 樹莓派須要先安裝BCM2835
1. 該軟件在樹莓派3B (Raspbian GNU/Linux 8.0 jessie)上面開發、測試
2. 最新文檔和代碼請查看https://github.com/LanFly/Device
3. 在除樹莓派以外的平臺經過npm安裝此軟件包可能會安裝失敗
4. 該軟件依賴不少第三方軟件,並修改了其中的代碼,感謝各位大佬的開源
5. 因我的時間有限,且硬件種類繁多,代碼中可能有還沒有測試到的bug,能夠經過下面的聯繫方式反饋給我並尋求幫助
6. 我會持續集成其它種類的驅動,若有硬件沒驅動的同窗,能夠反饋給我
7. i2c包的做者已經N年不更新了,裏面有個bug,pull request也不處理。使用ssd1306的時候可能會有點問題,本身改一行代碼就好了。
複製代碼
能夠引入全部的模塊,也能夠單獨使用某一個模塊。緩存
var Device = require('onedevice');
複製代碼
var XFS5152CE = require('onedevice/lib/device/xfs5152ce');
複製代碼
new Device(option);
複製代碼
description
: String服務器
此設備的描述。默認值:String('this device has not description')
model
: String
此設備的具體型號,若是配置了此選項,則根據型號返回對應的硬件驅動實例。若是device
沒有該型號的驅動,則返回null。
目前device集成的驅動型號有:
interface
: String
此通用設備的通訊方式。該選項適用於建立一個自定義設備驅動,或者device沒有集成的設備。例如STC89C52RC單片機使用串口跟樹莓派通訊,則你能夠建立一個串口設備,讓你能和單片機交換數據,而後本身擴展應用層的邏輯驅動。
對於大部分的傳感器或模塊,都使用了常見的通訊協議,例如:i2c、uart、spi、one-wire。驅動這些設備相對來講簡單,由於你無需關心這些協議的原理,只須要處理髮送和接受數據。
device集成的科大訊飛驅動就是經過建立uart串口驅動,而後實現say,sleep,setVolume等函數的。
device目前集成的通訊協議有:
address
: String || Int
此設備的物理接口地址或者I2C從機設備的邏輯地址。若是此設備是串口協議的設備,則此字段表示設備在主機上的物理接口地址。例如USB轉串口設備,則它的地址多是字符串/dev/ttyUSB0
。
若是此設備是使用I2C協議的設備,則它的值表示該I2C設備的邏輯地址。例如SSD1306模塊,它的值多是Int0x3C
,通常用16進製表示,固然你喜歡也能夠用10進製表示。
device
: String
I2C設備在主機上的物理接口地址。I2C設備用2個地址來標識,第一個是物理接口地址,第二個是I2C從機的邏輯地址。爲何要2個地址?由於樹莓派GPIO提供了2個I2C物理接口,device須要知道你的設備跟主機上的哪一個接口相連。
它有下面2個可選值:
你可使用i2cdetect
工具來掃描接在總線上的全部I2C設備,並列出他們的邏輯地址。該工具須要先安裝才能使用。
xfs5152ce這款文字轉語言芯片可使用I2C、SPI、串口等方式通訊,使用3.3V便可知足供電,我使用的是某寶上面的xfs5152ce模塊,帶3W功放,我使用5V電源比較穩定。
這裏使用串口通訊驅動模塊,波特率通常爲9600,波特率根據本身的狀況設置。
var Device = require('onedevice');
var xfs5152ce = new Device({
description: 'xfs5152ce module',
model: 'xfs5152ce',
baudRate: 9600,
address: '/dev/ttyUSB0'
});
複製代碼
上面返回一個串口驅動的實例,address
參數是串口的地址。爲何是串口驅動?由於咱們用的是串口方式驅動芯片的。你須要等待串口打開成功才能使用芯片。
xfs5152ce.on('open', function(next){
xfs5152ce.say('你好,科大訊飛!');
next();
});
xfs5152ce.on('error', function(error, next){
console.log(error);
next();
});
複製代碼
最好在open回調事件中使用串口功能,在open事件觸發後,你就能夠發送任意長度的文本給芯片朗讀。
say函數會自動維護朗讀隊列。若是當前的文本沒有朗讀完,再次調用say函數會放到隊列中,朗讀完後自動從隊列中取出第一個朗讀,直到隊列中全部的都朗讀完。
open
,error
,data
事件都支持中間件,這跟express框架的洋蔥模型是差很少的。next方法表示下一個中間件,它支持參數,表示更改傳遞給下一個中間件的數據,此更改只做用下一個中間件。請看下面例子。
// 假設串口返回的數據是 data === 1
xfs5152ce.on('data', function(data, next){
console.log('md-1-start: ', data);
next(data + 1);
console.log('md-1-end: ', data);
}).on('data', function(data, next){
console.log('md-2-start: ', data);
next();
console.log('md-2-end: ', data);
}).on('data', function(data, next){
console.log('md-3-start: ', data);
next();
console.log('md-3-end: ', data);
});
複製代碼
上面的執行結果以下:
md-1-start: 1
md-2-start: 2
md-3-start: 1
md-3-end: 1
md-2-end: 2
md-1-end: 1
複製代碼
XFS5152CE驅動實例實現瞭如下函數:
@params {String} text: 必需。要朗讀的文本。能夠帶上文本控制標記
@params {Boolean} imediately: 可選。是否當即朗讀。若是爲true,會中斷當前正在朗讀的指令。
@params {function} callback: 可選。發送朗讀指令成功的回調。
儘快朗讀文本。驅動實現了語音指令緩存,上位機能夠連續的屢次調用朗讀函數,而後去處理其它任務。驅動會按照前後順序,自動朗讀完全部語音指令。若是imediately爲true,則會中止正在朗讀的全部文本,轉而當即朗讀text。
@params {integer} volume: 設置朗讀的音量。對正在朗讀的文本無效。
設置朗讀的音量。可選值爲1到10之間的整數。包含1和10。1位最小音量,10爲最大音量。默認音量爲3。設置音量後僅對後面的語音指令有效,對正在朗讀的文本不影響。後面優化成實時設置音量。
@return {integer}
返回朗讀的音量。
@params {function} callback: 進入省電模式成功後的回調
讓芯片進入省電模式。發送省電指令後,芯片當即中止當前全部指令,此時芯片的工做電流爲5mA。
@params {function} callback: 退出省電模式成功後的回調
讓芯片恢復到待合成模式。進入待合成模式時,驅動會自動朗讀當前未朗讀的文本。
@return {integer}
返回當前未朗讀的語音合成指令數。每調用一次say函數,就會增長一個語音合成指令數量。
@return {boolean}
返回芯片是否正在朗讀文本。
@params {string} type: 監聽的事件類型,能夠是data、open、error
@params {function} callback: 當事件觸發時須要執行的函數
註冊指定事件的回調,當事件發生時會執行回調函數。能夠鏈式調用。採用和express類似的洋蔥模型。
事件類型不一樣,callback回調的參數也不一樣:
data: function(data, next) data是接收到的數據。也多是上一個中間件中調用next(data)傳遞過來的data
open: function(next)
error: function(error, next) error是發生錯誤時的信息。
這些設備比較簡單,使用單總線的方式,只須要一根數據線和樹莓派相連。剩下2根是電源線,分別鏈接正極和負極。也能夠不使用電源線,只使用一根數據線完成數據的讀取、發送,而且從數據線上獲取設備所須要的電源。具體請另行查閱單總線的寄生電路。
var dht11 = new Device({
model: 'dht11',
description: 'dht11 sensor',
address: 4
});
複製代碼
address是傳感器的數據線鏈接在樹莓派GPIO的編號。採用BCM GPIO編號。
dht11.fetch(function(error, temperature, humidity){
if (error) {
console.log(error.message);
}else{
console.log('溫度: ' + temperature.toFixed(2) + ' 溼度: ' + humidity.toFixed(2));
}
});
複製代碼
讀取傳感器數據比較簡單。注意:DHT11採樣週期是1s,建議連續讀取數值至少間隔1s以上,不然可能會引發錯誤。DHT22採樣週期2s,建議連續讀取數值至少間隔2s以上。
適合市面上常見的以SSD1306爲主控的小型OLED顯示屏,分辨率在128128之內。大於128128分辨率的未測試,底層驅動使用的是oled-ssd1306-i2c
npm包,它能驅動的均可以驅動。
var ssd1306 = new Device({
description: 'ssd1306',
width: 128,
height: 64,
address: 0x3c,
device: '/dev/i2c-1'
});
複製代碼
width、height分別表示分辨率的寬和高。address是i2c的從機地址,這個因硬件設備有所不一樣,你們本身瞭解清楚。device是i2c設備接在樹莓派上的接口地址,這個也是因人而異。對於SPI接口的OLED,目前尚未集成驅動,後續會加上。
如今,我要如何控制屏幕顯示的內容?
ssd1306.drawPNG('path/to/image.png', false, function(error){
if (error) {
console.log(error);
}else{
console.log('顯示PNG圖片完成');
}
});
複製代碼
注意,只能爲PNG圖片。爲達到最理想的顯示效果,PNG圖片的分辨率最好和OLED屏幕的分辨率一致。OLED是隻有單色的,不支持彩色,因此顯示的時候圖片會自動轉換爲單色圖片,而後再顯示。有色值的像素點在屏幕上會被點亮,透明的像素點會被熄滅。
var Canvas = require('canvas');
var canvas = new Canvas(128, 64);
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#FFF';
ctx.fillText("Hello world", 0, 0);
// 上面5行代碼應該不須要解釋吧。都是canvas操做
// 結果就是在canvas上會在左上角顯示一行白色的'hello world'文字
// 而後把canvas的內容顯示到屏幕上
ssd1306.drawCanvas(canvas);
複製代碼
這時你應該能在屏幕上看到'hello world'文字了。drawCanvas函數會把canvas上的像素點一一對應到屏幕上繪製(固然也支持只繪製指定部分的canvas)。因此,你的canvas顯示什麼,屏幕就會顯示什麼。經過程序不斷的更新canvas,而後在合適的時機調用drawCanvas函數刷新屏幕,你就能夠控制屏幕了。
使用canvas的好處不須要我解釋了,學習成本低,完善的API文檔,大量的教程,和各類強大的canvas庫。
須要注意的是,爲了達到最理想的顯示效果,canvas的分辨率最好和屏幕的分辨率一致,而且使用單色繪製canvas,建議用#FFF。由於不管如何,你的OLED都是單色的屏幕,沒法顯示彩色。雖然有彩色的OLED,但目前還沒集成驅動。後續會集成更大尺寸的彩色LCD、TFT屏幕驅動。這是個巨大的工程,但願有懂這方面的軟硬件工程師協助我。
在node中使用canvas須要先安裝。API和在瀏覽器HTML5中的canvas稍微有點區別。請自行查閱資料安裝並使用。
前面說了,這是基於oled-ssd1306-i2c
封裝的。它自身已經提供了一套簡易的圖形API用於操做屏幕。好比常見的繪製像素,直線,矩形,圓,文字等。使用這個的好處是不須要安裝node-canvas,沒有依賴。輕便、簡單。怎麼用?
它的全部API都掛載在驅動實例的oled
屬性上。例如:
ssd1306.oled.drawLine(1, 1, 128, 64, 1);
複製代碼
上面使用自帶的API繪製一條從(1, 1) 到 (128, 64) 的直線。oled屬性就是oled-ssd1306-i2c
的實例。更多API請自行查閱它的文檔。
目前node驅動SSD1306屏幕有個缺點,就是刷新率過低,在個人樹莓派3B上最高也就10幀。使用Python能達到30幀流暢。若是使用C++,則能夠很容易達到60幀。我正在努力嘗試提升它的刷新率。
@params {Canvas} canvas: 要繪製的node-canvas。
@params {Object} config: 可選。配置要繪製的canvas的區域。默認從左上角開始繪製和屏幕同樣大的區域。它有下列幾個屬性:
{
sx: 開始繪製的點的橫座標。
sy: 開始繪製的點的縱座標
sw: 要繪製的矩形的寬度
sh: 要繪製的矩形的高度
}
複製代碼
複製canvas的像素,一一對應到屏幕上並顯示。經過ctx.getImageData函數獲取canvas的像素信息。繪製前,會處理掉canvas的彩色像素。建議使用#FFF顏色進行繪製。有顏色的像素會被點亮,其他會被關閉。
@params {string} filename: 要繪製的PNG圖片路徑
@params {boolean} dither: 可選。是否啓用抖動算法處理圖片像素,默認爲false。
@params {function} callback: 繪製圖片完成時的回調。若是繪製錯誤,回調函數經過參數傳遞error。成功時爲null。
在屏幕上繪製PNG圖片。爲達到最理想的顯示效果,PNG圖片最好是單色的,背景透明。經過pngparse
npm包處理圖片的像素信息。抖動算法使用的是floyd-steinberg
npm包。
@params {Number} second: 刷新屏幕的間隔時間,單位秒。若是不傳,或傳0,則只顯示一次。不然會自動每隔幾秒刷新一次。
顯示系統信息,在屏幕上顯示CPU、內存的統計信息,以及IP地址、時間。若是指定了一個時間,則會自動每隔幾秒刷新。
中止刷新系統信息
串口使用很是廣泛,也很是簡單。建立一個串口設備很容易。在樹莓派上面使用串口最簡單的方式就是某寶買一個USB轉串口,例如常見的使用ch340芯片的STC下載器,只須要10塊錢包郵,免驅,還自帶3.3V和5V電源接口,很是方便。
var stc89c52rc = new Device({
description: 'stc89c52rc',
interface: 'serial',
address: '/dev/ttyUSB0',
baudRate: 9600
});
複製代碼
上面是使用USB轉串口和單片機的串口引腳相連,單片機設置好波特率,樹莓派和單片機之間就能夠互相傳輸數據。串口是基於serialport
這個很是受歡迎的npm包封裝的。串口設備的serial
屬性是serialport
的實例,該屬性下面有全部它的方法和屬性。可自行查閱它的文檔。
串口驅動實例有下面這些方法:
請參考XFS5152CE部分API文檔
@params {buffer || array} data: 要發送的數據。能夠是buffer或者是array,固然也能夠是字符串,以二進制流發送。
@params {function} callback: 發送數據成功後的回調。若是發送錯誤,則經過參數傳遞error。
向串口設備發送數據。發送時以二進制流發送。
@params {string} name: 驅動的名字
@params {function} driver: 實現驅動的方法
未通用設備註冊自定義驅動。實際就是向實例中添加一個屬性名爲name的driver函數。這樣實例即可以直接調用這個函數。只不過driver函數的運行時this指向該實例。例如xfs5152ce就是經過建立通用串口設備,而後註冊驅動函數實現的。
serial.driver('say', function(text, imed, cb){
......
}
複製代碼
I2C設備稍複雜點,由於它是一對多的。數據的讀取和發送都是經過主機控制。樹莓派自帶I2C接口,因此不須要其它硬件就可使用。不少模塊也是使用i2c協議的,例如常見的AT24C02 CMOS EEPROM存儲器就是使用I2C的典型。單片機教程中常用該例子進行I2C操做的學習。
var i2c = new Device({
description: 'test i2c',
interface: 'i2c',
address: 0x3c,
device: '/dev/i2c-1'
});
複製代碼
注意i2c通用設備的address地址不是指i2c的物理接口地址,而是指的從機的邏輯地址。device纔是指接口的物理接口地址。i2c驅動是基於i2c
這個很是受歡迎的npm包封裝的。實例的i2c屬性就是i2c
的實例,它擁有全部的方法和屬性,能夠自行查閱i2c的文檔。SSD1306就是經過建立通用i2c設備,而後經過寄存器操做驅動屏幕。
i2c實例有如下方法:
參考上面的driver文檔。
由於i2c方法太多,這裏就沒有進行封裝了,能夠經過i2c屬性訪問各函數。
有些更高級的模塊使用網絡進行數據傳輸。例如ESP 8266 WiFi模塊,能夠將串口的數據經過WiFi以UDP或TCP協議發送出去。這個就好玩了,經過將8266和單片機串口相連,能夠很容易的讓單片機實現網絡鏈接。讓單片機去採集數據,經過網絡發送給樹莓派,或者樹莓派發送控制命令,遠程遙控單片機。8266模塊使用UDP是最簡單的方法。
var esp = new Device({
description: 'stc89c52rc-wifi',
interface: 'udp',
type: 'udp4',
address: '127.0.0.1',
port: 8266,
remoteAddress: '192.168.1.80',
remotePort: 8266,
reuseAddr: false
});
複製代碼
使用udp須要配置在本地監聽服務器的地址和端口,同時也要指定對方的IP地址和端口。通常給8266模塊配置固定IP。
UDP驅動實例有如下方法:
@params {string} type: 事件類型。能夠取值爲: listening、close、error、message。
@params {function} callback: 事件發生時的回調。不一樣的事件類型有不一樣的參數。具體以下:
@type: listening 當本地監聽服務器啓動後發生
沒有參數
@type: close 當本地監聽服務器關閉後發生
沒有參數
@type: error 當監聽服務器發生錯誤時發生
callback(error)
@type: message 當服務器接受到數據時發生
callback(data, remote, next)
data是接收到的數據。buffer類型。
remote是node dgram的內置對象。請參考node文檔。
next請參考上面xfs5152ce驅動的文檔。
複製代碼
@params {buffer} data: 要發送的數據。
@params {function} callback(error): 發送數據成功或失敗後的回調。
參考上面的driver文檔。
寫驅動不易,除了編寫軟件外,還須要購買硬件實物,沒法像軟件同樣即寫即所得。
還有不少不完善的地方,不管是API設計到代碼組織,都須要好好思考。後續會增長更多驅動和完善通用性驅動的功能。大部分驅動都是以通用性設備做爲基礎,而後按照硬件要求的數據格式進行傳輸,達到讓硬件工做的方式。因此有必要完善好通用性驅動的功能。
更友好的API文檔也是後續要作的事。
總之,這只是開始。
你們用的開心就好,反正也是給我本身用的。
v0.0.2 @ 2018-04-22 17:19
v0.0.1 @ 2018-01-01 23:27