LINE Bot聊天機器人程式開發教學(七):從ESP8266/Arduino控制板觸發Line發布訊息

美國亞馬遜Amazon購物商城於2015年三月底推出名叫Dash Button的物聯網裝置,它是一個無線聯網的按鈕,按一下按鈕就能下單購買該按鈕代表的商品:

Amazon Dash Button

本文將使用ESP8266控制板(如:NodeMCU或Wemos D1 mini)製作「一鍵」發Line訊息的物聯網按鈕。假設在廚房放一個物聯網按鈕,按下它就發Line通知老公洗碗;在門口放一個按鈕,按一下Line就會發送空氣品質訊息;把按鈕改成「磁簧開關」安裝在門窗,或者「PID人體紅外線偵測器」,這個小裝置就變成防盜器,若門窗被打開,Line就會發送入侵通知。

從ESP8266控制板觸發Line發送訊息

透過Line推送(push)與群發(multicast)訊息

Line開發者帳號支援推送訊息功能,指令語法如下:

psuh(推送)訊息指令

其中的使用者ID並不是Line App的「個人資料」欄位裡顯示的ID,而是Line指派的唯一識別碼,你可以在你的Line應用程式的Channel settings(頻道設定)頁面QR Code下方的Other(其他)單元看到你的Line ID:

Line使用者ID

或者,對「LINE Bot聊天機器人程式開發教學(六):讀取並傳回空氣品質狀況給使用者」文章的Line聊天機器人發送‘Me’訊息,它也會回覆你的Line ID。「訊息物件」的「訊息類型」,可以是文字、圖像、貼圖…等格式,詳請參閱Line技術文件的Message objects單元

若要同時發送訊息給多人,可先用陣列存放使用者的Line ID

用陣列存放使用者的Line ID

再透過multicast()方法傳送訊息:

multicast()方法傳送訊息

底下的程式片段將會同時發送文字和圖像

bot.push('Line用戶ID', [{
    type: 'text',
    text: '零食櫃被打開了!'
  },
  {
    type: 'image',
    // 原始圖像的網址
    originalContentUrl: 'https://swf.com.tw/images/books/IoT/webcam_face_detection.png',
    // 預覽圖像的網址
    previewImageUrl: 'https://swf.com.tw/images/books/IoT/raspberry_pi.png'
}]);

其中的「預覽圖像」尺寸上限240 x 240,檔案大小不得超過1MB;「原始圖像」尺寸上限1024 x 1024,檔案大小不得超過1MB,詳閱Line API文件的image單元

由於本文使用的Heroku雲端應用程式平台不支援寄存圖檔,所以筆者直接引用放在本網站裡的圖片。你可以先把圖檔上傳到flikr, dropbox, google drive….等任何雲端儲存空間,再分享網址給你的Line程式使用。

處理ESP8266訊息發送請求的Node.js程式

假設我們打算佈署3個連接Line的ESP8266控制板,為了區別這些板子,每個控制板都被設置了唯一的識別名稱

設置唯一識別名稱的ESP8266控制板

負責處理Line訊息的node.js程式,將新增一個處理/btn路徑的路由,並接收包含key(密碼)和id(裝置識別名稱)參數的查詢字串:

處理Line訊息的/btn路徑

設置密碼是為了避免Node路由被隨意觸發,處理/btn資源請求的node.js程式片段如下,若密碼錯誤,它將回應HTTP 401認證錯誤訊息,在網頁上顯示“ERROR!”;若密碼驗證成功,則在網頁上呈現接收到的識別名稱

處理/btn資源請求的node.js程式片段

加上推送Line訊息的程式碼如下,它將依據控制板傳入的識別名稱,決定要發送什麼訊息。

加上推送Line訊息的程式碼

底下是完整的node.js碼(index.js檔),請參閱「LINE Bot聊天機器人程式開發教學(六):讀取並傳回空氣品質狀況給使用者」文末的操作說明,將它上傳到Heroku雲端應用程式平台。

const linebot = require('linebot');
const express = require('express');
const rp = require('request-promise');
const bodyParser = require('body-parser');

const passcode = '你的自訂密碼';
const ME = '你的Line使用者ID';

const SITE_NAME = '西屯';
const aqiOpt = {
    uri: "http://opendata2.epa.gov.tw/AQI.json",
    json: true
}; 

const bot = linebot({
	channelId: process.env.CHANNEL_ID,
	channelSecret: process.env.CHANNEL_SECRET,
	channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN
});

function readAQI(repos){
    let data;
    
    for (i in repos) {
        if (repos[i].SiteName == SITE_NAME) {
            data = repos[i];
            break;
        }
    }

    return data;
}

const app = express();
app.set('view engine', 'ejs');

const linebotParser = bot.parser();

app.get('/',function(req,res){
    rp(aqiOpt)
    .then(function (repos) {
        res.render('index', {AQI:readAQI(repos)});
    })
    .catch(function (err) {
		res.send("無法取得空氣品質資料~");
    });
});

app.get('/btn', function(req, res) {
	if (req.query.key !== passcode) {
		res.status(401).send('ERROR!');
	}

	let id = req.query.id;
	res.send("id: " + id);

	switch (id) {
		case 'wash_dish':
			bot.push(ME, {
				type: 'text',
				text: '女王呼喚:\n\n快去洗碗!!'
			});
			break;

		case 'candy':
			bot.push(ME, [{
				type: 'text',
				text: '零食櫃被打開了!'
			},
			{
				type: 'image',
				originalContentUrl: 'https://swf.com.tw/images/books/IoT/webcam_face_detection.png',
				previewImageUrl: 'https://swf.com.tw/images/books/IoT/raspberry_pi.png'
			}]);
			break;

		case 'air':
			let data, msg;
			rp(aqiOpt)
			.then(function (repos) {
				data = readAQI(repos);
				msg = data.County + data.SiteName +
				'\n\nPM2.5指數:'+ data["PM2.5_AVG"] + 
				'\n狀態:' + data.Status;

				bot.push(ME, {
					type: 'text',
					text: msg
				});
			})
			.catch(function (err) {
				bot.push(ME, {
					type: 'text',
					text: '無法取得空氣品質資料~'
				});
			});
			break;

	}

});

app.post('/linewebhook', linebotParser);

app.get('*', function(req, res) {
	res.status(404).send('找不到網頁!');
});

bot.on('message', function (event) {
	switch (event.message.type) {
		case 'text':
			switch (event.message.text) {
				case '空氣':
					let data;
					rp(aqiOpt)
					.then(function (repos) {
						data = readAQI(repos);
						event.reply(data.County + data.SiteName +
						'\n\nPM2.5指數:'+ data["PM2.5_AVG"] + 
					    '\n狀態:' + data.Status);
					})
					.catch(function (err) {
						event.reply('無法取得空氣品質資料~');
					});
					break;

				case 'Me':
					event.source.profile().then(function (profile) {
						return event.reply('Hello ' + profile.displayName + ' ' + profile.userId);
					});
					break;
			}
			break;
		case 'sticker':
			event.reply({
				type: 'sticker',
				packageId: 1,
				stickerId: 1
			});
			break;
		default:
			event.reply('Unknow message: ' + JSON.stringify(event));
			break;
	}
});

app.listen(process.env.PORT || 80, function () {
	console.log('LineBot is running.');
});

上傳到Heroku之後,你可以先用瀏覽器測試,輸入底下的網址,你的Line聊天機器人將會推送「洗碗」的訊息:

處理Line訊息的/btn路徑

觸發Line聊天機器人的ESP8266/Arduino程式

本範例程式修改自《超圖解物聯網IoT實作入門》第12章「讓NodeMCU扮演網路前端上傳資料(IFTTT)」一節,使用NodeMCU內建的Flash按鈕來觸發執行前端程式。

完整的ESP8266程式碼如下,請自行修改Heroku應用程式名稱,以及你在上文的Node.js程式裡面設定的密碼。此控制板的名稱設定成 “wash_dish”:

#include <esp8266wifi.h>;
#include <esp8266httpclient.h>;

const char* ssid = "無線網路名稱";
const char* pass = "無線網路密碼";

const byte BTN_PIN = 0;     // 按鈕/開關接腳
const byte LED_PIN = 2;     // LED接腳

unsigned long previousMillis = 0;
const long interval = 60000;     // 60秒

HTTPClient http;

void line() {
http.begin("你的應用程式名稱.herokuapp.com", 80, "/btn?key=你的密碼&id=wash_dish");
int httpCode = http.GET();
if(httpCode > 0) {
// 在序列埠監控視窗顯示送出的數據
Serial.printf("HTTP code: %d\n", httpCode);

if(httpCode == 200) {
String payload = http.getString();
// 顯示遠端伺服器的回應
Serial.println(payload);
}
} else {
Serial.println("HTTP connection ERROR!");
}
}

void setup() {
pinMode(LED_PIN, OUTPUT);
pinMode(BTN_PIN, INPUT_PULLUP);

Serial.begin(9600);
WiFi.begin(ssid, pass);

Serial.println("");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Wi-Fi ready...");
}

void loop() {
unsigned long currentMillis = millis();
boolean btnState= digitalRead(BTN_PIN);

    if (btnState == LOW) {
// 點亮LED
digitalWrite(LED_PIN, LOW);
if ((previousMillis == 0) || (currentMillis - previousMillis) >= interval) {
previousMillis = currentMillis;
line();
}
} else {
// 關閉LED
digitalWrite(LED_PIN, HIGH);
}
}

編譯並上傳到NodeMCU控制板後,開啟序列埠監控視窗,等待控制板Wi-Fi連線成功,再按下控制板的Flash按鈕,它將連結到你的Heroku應用程式並接收伺服器的回應,而Line機器人也將推送訊息給你。

序列埠監控視窗

延伸閱讀

Posts created 467

54 thoughts on “LINE Bot聊天機器人程式開發教學(七):從ESP8266/Arduino控制板觸發Line發布訊息

  1. Hello Cubie,

    每次看完你的文章, 總是會想再把東西拿出來實作一遍. 想請教一下, 是否有想過出一本專門針對ESP8266的教學書?! 因為它真的CP值很高, 而且台灣針對ESP8266的教學書, 真的很少… 目前我只有看過一本而已. 超圖解的二本書籍我都入手了, 很期待你下一次的新作~~~

    1. 請問這個可以跟清淨機與氣體模組做搭配嗎 當偵測到高於標準的氣體濃度時,就會傳訊息到LINEBOT ,藉由LINEBOT把清淨機打開進行運作

    2. 可行,但直接從微控器發射紅外線遙控訊號控制空氣清靜機即可,不必透過Line Bot。

      thanks,
      jeffrey

    3. 請問 我想做出系統語音訊息處理透過手機無線控制與偵測 使用人講話聲音控制 如果只想用line bot的話 請問要跟arduino哪個開發板做搭配 軟體與硬體要怎麼搭配 還有系統建立語音的方式及網路介面 問題有點多請見諒

    4. 請問你提供的相關範例請參閱Speak to Arduino and Control It with Google Assist是否可搭配手機做語音控制與從手機上做監控偵測 的功能

  2. 老師您好:
    在LINE Bot聊天機器人程式開發教學中,您使用了Heroku平台應用程式,有兩個問題想請教

    1. 如果Heroku平台應用程式未來不提供這個服務或是有修改這個服務的話的話,這個LINE Bot聊天機器人程式就失效了
    2. 如果要主動推送訊息給已經是line好友,很難去取得他們的user id,您提供了兩種方式去取得自己的user id如下
    (1) 在你的Line應用程式的Channel settings(頻道設定)頁面QR Code下方的Other(其他)單元看到你的Line ID:
    (2) Line聊天機器人發送‘Me’訊息,它也會回覆你的Line ID

    但是這兩種方式還是很不容易取得line好友的user id,等於必須要問好友的user id 是甚麼,不知道有沒有不用麻煩line好友就可以知道line好友的line user id的方式

    關於第一個問題,我想到的就是直接佈署在自己的樹莓派就可以了

    1. 1. 提供雲端應用平台和網站空間服務的公司很多,如果Heroku不存在了,換一家就好……我覺得這個機率比Line公司修改開發人員服務條款還要低,不用擔心。
      2. 使用者將Line聊天機器人加入好友之後,後端程式就能取得他們的User ID了,所以這應該不成問題。

      thanks,
      jeffrey

    2. 老師您好:
      在LINE Bot聊天機器人程式開發教學中,有一些問題想請教

      1. 雖然提供雲端應用平台和網站空間服務的公司很多,但是或多或少還是有些限制,

      (1)例如您在LINE Bot聊天機器人程式開發教學(七)文中提到Heroku雲端應用程式平台不支援寄存圖檔,
      (2)或者不支援MongoDB資料庫或MySQL資料庫的功能,
      (3)或者如果推送的型態視訊類型的話,我們把index.js佈署在樹苺派上,並且把網路攝影機接在樹莓派上,就可以將樹莓派錄好的視訊或串流的視訊推送給line好友,不知道是否可行

      2. 另外老師提到line好友加入Line聊天機器人後,可以透過後端程式取得line好友的User ID,不知道這個後端程式該如何撰寫呢?

    3. 1. 我二月份會更新文章說明佈署在樹莓派的方式。
      2. 附加照片的例子可用書本第六章的「雲端蒐證∕拍照自動寄送e-mail」範例來修改。
      3. group id和user id都位於Webhook事件物件的source物件裡面,Line官方的API文件有說明。

      thanks,
      jeffrey

  3. 老師您好:

    我把line機器人的Allow bot to join group chats選項設定成enable,並將line機器人加入我的line群組,群裡的人只要對群裡發 ‘空氣’ 文字和貼圖都會有反應,想請問這個line機器人也可以推送訊息、貼圖、影片、圖片、聲音到這個line群組嗎? 可是group id要如何取得呢?

    我參考了https://developers.line.me/en/docs/messaging-api/reference/#common-properties,還是沒看到,請老師指導一下,感謝老師的幫忙

  4. 老師您好:
    我改您的程式可以得到Group id

    case ‘Me’:
    event.source.profile().then(function (profile) {
    return event.reply(‘Hello ‘ + profile.displayName + ‘ ‘ + profile.userId);
    });
    break;
    case ‘Group’:
    event.reply(‘Hello ‘ + event.source.groupId);
    break;

    另外改

    const users = [‘XXXXXXXXXXXX’,
    ‘XXXXXXXXXXXX’];

    const groups = [‘XXXXXXXXXXXX’,
    ‘XXXXXXXXXXXX’];

    bot.push(groups, {
    type: ‘text’,
    text: msg
    });
    bot.push(users, {
    type: ‘text’,
    text: msg
    });

    並不需要用到multicast,謝謝

  5. 老師您好:

    在Line官方的API文件中,看到了以下:

    Get group member profile

    HTTP request
    GET https://api.line.me/v2/bot/group/{groupId}/member/{userId}

    Response
    1. displayName
    2. userId
    3. pictureUrl

    以及

    Get group member user IDs

    HTTP request
    GET https://api.line.me/v2/bot/group/{groupId}/members/ids

    Response
    1. memberIds
    2. next

    從老師的程式中增加了三項如下,因為程式佈署在Heroku平台,沒辦法看到終端機程式執行的結果,所以只能從
    line中去看結果,但是其中Group_member_profile 和 Group_user_ids 沒辦法顯示出來,所以想請教老師程式該如何修改,才能得到
    line群裡user的displayName,userId,pictureUrl以及line群裡所有人的memberIds

    case ‘Group’:
    event.reply(‘Hello ‘ + event.source.groupId);

    case ‘Group_member_profile’:
    bot.get(‘/group/’ + event.source.groupId + ‘/member/’ + event.source.userId).then(function (res) {
    return event.reply(res.json());
    });

    case ‘Group_user_ids’:
    bot.get(‘/group/’ + event.source.groupId + ‘/members/ids’).then(function (res) {
    return event.reply(res.json());
    });

  6. 老師您好

    在超圖解物聯網IoT書中第12-30頁中,有示範如何在區域網路中用網頁去控制連接在NodeMCU的LED的開關,
    請問如果改用line輸入文字來控制NodeMCU的LED開關,以老師這個LINE Bot聊天機器人程式該如何延伸修改呢?

    因為無法排版,所以硬體架構改用文字敘述,

    1. Led連接nodemcu,nodemcu無線連線到ip分享器
    2. 樹莓派(webhook url)無線連線到ip分享器
    3. ip分享器連上internet
    4. 在line上發送文字訊息透過internet連到ip 分享器及樹莓派上的webhook,webhook接收來自line的訊息,傳送http request 給nodemcu上的web server控制連接在nodemcu上的led

    謝謝老師

    1. 程式架構一樣,ESP8266當作Web Server,只是網頁端的程式改用Node.js的request模組連結家中的ESP8266控制板(此Node.js程式可放在Heroku)。

      為了讓外部程式透過IP位址連結到家中的控制板,你的IP分享器必須開啟虛擬非軍事區之類的服務,詳細設置步驟請參閱你的IP分享器說明書。

      thanks,
      jeffrey

    2. 老師您好

      在超圖解物聯網IoT書中第12-30頁中,有示範如何在區域網路中用網頁去控制連接在NodeMCU的LED的開關,我使用了在樹莓派的方式直接去控制同區域網路的NodeMCU上的LED,並使用了ngrok這個工具,讓我的樹莓派能直接使用https協定,並把ngrok產生https 的webhook設定在line Message API上,已經可以在line上用文字開關LED,這個做法好處是可以不用去設定ip 分享器的虛擬伺服器,且可以存取樹莓派上的資源,供老師做參考,謝謝老師的幫忙

      參考網址
      https://simonhsu.blog/2017/01/25/%E4%B8%8D%E5%BF%85%E7%9C%9F%E7%9A%84%E6%9E%B6%E7%AB%99%E4%B9%9F%E8%83%BD-5-%E5%88%86%E9%90%98%E5%AF%A6%E6%A9%9F%E9%AB%94%E9%A9%97-line-bot-message-api-%E6%87%89%E7%94%A8-by-node-js-ngrok/

  7. 老師您好
    另外想到一個line聊天機器人的應用,就是當line使用者拍一張花的照片傳給line聊天機器人後,照片能自動下載到樹莓派上做分析,經過樹莓派上的影像辨識程式(node.js 程式)辨別是哪一個花種,分析完後便將結果傳回給line使用者,有兩個問題需要解決

    1.如何讓line使用者拍的照片能傳給line聊天機器人後,自動下載到樹莓派
    2.如何針對已經下載到樹莓派上的照片做影像辨識花種

    在第1個問題,我還沒找到如何讓line使用者拍的照片能傳給line聊天機器人後,自動下載到樹莓派
    在第2個問題,我在參考超圖解物聯網IoT書中6-42頁的openCV,正在研究當中

    以上兩個問題,希望老師能給予建議,謝謝老師的幫忙

    1. Line的影像有解析度和檔案大小限制,而且就使用情境來說,我覺得你設想的程式應該是個獨立的App,開啟之後直接掃描,或者是相機App的外掛。像三星的Bixby Vision(人工智慧影像比對和搜尋)功能,可以識別葡萄酒的標籤,拍照之後回應葡萄酒的產地、年份以及建議搭配的食物等資訊,如這段YouTube影片所示;市面上有許多OpenCV和機器學習等的相關書籍,預祝你研究順利!

      thanks,
      jeffrey

  8. 老師您好,依此範例,如果我想將按下按鈕後將訊息傳到line群組裡要如何修改呢?

  9. 老師您好:

    我有必須連續使用line()的需求,準確來說是要連續發送GET請求,但是我發現當我連續使用時會有一小段的延遲時間,似乎很少文章在討論這件事,請問老師對這個問題有甚麼看法或解決方法嗎?

  10. 老師好,拜讀您的大作《超圖解Python程式設計入門》&《超圖解Python物聯網實作入門》,目前卡在我使用ESP8266晶片進行按鈕與Line的溝通,但一直卡在import urequests 模組,因為無法使用 urequests.get函式,錯誤資訊:AttributeError: module ‘urequests’ has no attribute ‘get’

    請問我該如何解決此問題?謝謝

  11. 呈上問題,若我直接screen ESP8266,在裡面 測試 import urequests,則是出現以下錯誤:
    >>> import urequests as req
    >>> req.get(‘http://www.google.com’)
    Traceback (most recent call last):
    File “”, line 1, in
    File “urequests.py”, line 108, in get
    File “urequests.py”, line 53, in request
    OSError: -2

    請問我該如何解決(已經困擾我 一週了… XD)非常感恩

    1. 請問你燒錄的MicroPython版本?我剛剛在燒錄1.11版的ESP-01板子上測試,執行無誤。
      你也可以嘗試MicroPython 16-30頁的socket程式,以及17-23頁的urequests程式。

      thanks,
      jeffrey

  12. 老師您好,我燒錄的MicroPython版本有書本提到的20171101-v1.9.3版本,以及之後測試最新版(v1.11, v1.12)結果仍是一樣,然後我在ESP8266去 print(dir(urequest)),確實是有get函式
    >>> print(dir(urequests))
    [‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__path__’, ‘__spec__’]

    但很奇怪的是,我在系統下進入python3,
    >>> import urequests
    >>> print(dir(urequests))
    [‘__doc__’, ‘__file__’, ‘__loader__’, ‘__name__’, ‘__package__’, ‘__path__’, ‘__spec__’]
    竟然沒有get函式?
    pip3 list 版本: urequests 0.1.2

    實在不知道問題出在哪?
    另外,也請教一個很笨的問題,我在
    https://github.com/micropython/micropython-lib
    取得 urequests 模組後,我該如何放到 ESP8266上?
    應該不能直接 ampy put檔案上去吧,
    我又該如何查韌體 http://micropython.org/download
    bin檔案裡面的模組,是否有最新的github上的 urequests模組?

    非常感謝您的耐心回答

    1. Python 3(非控制板的MicroPython)的HTTP前端通訊程式庫叫做”requests”,名稱前面沒有”u”,請參閱「超圖解Python程式設計入門」11-2頁說明。

      MicroPython的urequests模組是內建的,不必再安裝。

      若要替MicroPython安裝程式庫,可以透過upip程式庫,請參閱「使用IFTTT串聯網路自動化服務(二)」貼文的「在MicroPython控制板安裝Python程式庫」單元。

      thanks,
      jeffrey

  13. 老師好,urequest無法使用get函式的問題依舊,我前前後後試了多個MicroPython版本,韌體只有最新的esp8266-20191220-v1.12.bin沒有urequests lib,其他2017年之後的都有,目前我安裝v1.11版。

    我有看到 http://github.com/micropython/micropython-lib/issues/153 我的問題和他一樣,有人回說要關閉socket,但我也看了您MicroPython 16-30頁的socket程式,我欲使用socket.getaddrinfo 函式,結果依樣出現了和urequest使用get的類似問題(如下)

    >>> socket.getaddrinfo(‘swf.com.tw’, 80)
    Traceback (most recent call last):
    File “”, line 1, in
    OSError: -2

    連socket都無法使用,我該如何關閉socket?
    還是說有可能是我的板子有問題(ESP8266-D1-m1n1板)? 旗標的板

  14. 老師好,有的,因為要測試GET, socket,一定要連上網路

    爬一下文,urequests也有部分網友提到說是要修改第53行程式碼
    https://forum.pycom.io/topic/2740/gpy-pysense-urequests-attributeerror-module-object-has-no-attribute-get/2

    但這部分我還尚未成功,也參考您的https://swf.com.tw/?p=1267
    說明如何在板子上更新lib,然而我光是upip.install(‘urllib.parse’)就一直出現以下錯誤:
    Installing to: /lib/
    Error: Unable to resolve micropython.org (no Internet?)

    但明明我都有連網啊? 真是奇怪……
    (無論走有線 or 無線,都測試,但結果皆同)

    1. 我認為問題不是出在socket和urequests程式庫,因為這兩者是很常用的程式庫,要是出現這麼顯著的錯誤,早就被修正了。

      如果不是聯網的問題,應該就是晶片有瑕疵了。

      thanks,
      jeffrey

  15. 老師好,這問題解決了,原來就是典型的「晶片要連結網路」的問題…….
    必須先連上網路就OK了(不是只有連接的電腦要連網,晶片要開network且不能有其他socket干擾),

    ps. 今天又搞了一片ESP8266發現都是同樣問題,後來才認知到犯了最基本的錯誤 Q.Q

    感謝您

  16. 老師好,我執行了《超圖解Python程式設計入門》附錄B的動手做B-1 觸發LINE聊天訊息,當我在ESP8266按下按鈕後,Line Bot確實可收到「去洗碗」的訊息,但ESP8266上的按鈕程式卻中斷,並出現以下錯誤訊息:
    TLS buffer overflow, record size: 16448 (+5)
    Traceback (most recent call last):
    File “”, lines 5, in
    File “urequests.py”, line 149, in get
    File “urequests.py”, line 116, in request
    OSError: -257

    我用D1 m1n1板子,請問是因為該板ram不夠的原因嗎? 我可以怎麼解決?謝謝

    1. 請問你執行的是附錄B的bot_sw.py程式嗎?
      附錄B的Line Bot只會回覆簡短的id訊息給控制板,並不會佔用多少記憶體。
      我剛剛測試了N遍,都沒有問題。

      thanks,
      jeffrey

  17. 是用書本裡的範例程式,但真的很怪,我試了兩個D1板,也嘗試分別安裝不同版本的韌體,輸出的錯誤都是一樣

    1. 我的測試步驟如下:

      1. 使用Flash Download Tools清除韌體、再燒錄韌體。
      2. 上傳包含連結Wi-Fi基地台敘述的boot.py檔
      3. 修改bot_sw.py檔的網址,連到包含Line Bot的herokuapp.com網站。
      4. 接好按鈕,測試OK。

      底下是稍做修改的MicroPython程式迴圈,它將顯示heroku網頁的內容:

      while True:
          if sw.value() == 0:
              time.sleep_ms(20)
              led.value(0)
              r = req.get(apiURL)
              while sw.value() == 0:
                  pass
              print(r.content)  # 顯示HTTP回應內容
          led.value(1)
      

      thanks,
      jeffrey

  18. 老師好,我測試了幾次後,發現附錄B(p.B-6 ~ p.B-8) 紙本上的程式即OK沒問題,反而是書本前面提到網路上的程式碼(F9796/附錄B/bot_iot.py),會出錯,只有部分語法不太一樣,但我仍找不出原因。

    1. 剛剛透過代理伺服器轉發本機網站執行bot_iot.py檔,發現問題了,因為’/btn’路由沒有回應HTTP訊息,所以前端(MicroPython)收到一堆警告訊息而導致overflow(溢位)。

      請把’/btn’路由的程式改成:

      @app.route('/btn')
      def btn():
          key = request.args.get('key')
          id = request.args.get('id')
      
          if key != passcode:
              return '<h1>出錯啦!</h1>', 401, {'ContentType': 'text/html'}
      
          if id == 'wash_dish':
              line_bot_api.push_message(ME, TextSendMessage(text='女王呼喚!\n快去洗碗!'))
              return f'id:{id}'  # 發出HTTP回應
          elif id == 'front_door':
              line_bot_api.push_message(ME, TextSendMessage(text='入侵警報!!!'))
              return f'id:{id}'
          else:
              return '請指定裝置代碼!'
      

      抱歉造成你的困擾,也非常感謝糾錯!

      thanks,
      jeffrey

  19. 您好,我想要讀取arduino上sensor監測到的數據,然後再用linebot接收數據,但是我該怎麼讓他直接去讀取arduino的數據呢?

    1. 您好,我想要做的是,linebot詢問→讀取arduino測量到的數據→傳回linebot,我主要是不知道讀取arduino數據我該怎麼做。我本身是沒有接觸過js的人,這次因為課程關係,我需要做一個物聯網相關的微專題,然後看到老師的文章,講的淺顯易懂,我想說可以試著做出來,不過卡在不知道該怎麼讀取數據,我有試著查過資料,可是還是不清楚該怎麼做

    2. 你需要兩個伺服器程式:
      1. Node.js:橋接Line訊息
      2. Arduino/ESP8266伺服器:接收與回應Node.js的連線請求。

      大致流程:

      Node.js伺服器接收Line訊息 → 發起連線請求到Arduino → Arduino讀取感測器資料回應給Node.js → Node.js回傳訊息給Line。

      廣告一下,上面的流程,在《超圖解Python程式設計入門》的附錄單元有Line控制開關實作,但程式分別用Python和MicroPython完成,我猜想你沒有時間換跑道了…

      thanks,
      jeffrey

    3. 是的,請問要如何達成nodejs與arduino的連結,並且讓arduino將資料回應給nodejs,nodejs接受line的訊息還有回傳訊息給line我藉由老師的文章,我可以看的懂知道該怎麼做,但是將nodejs與arduino連線,以及讓arduino資料回應給nodejs我是一頭霧水,實在不知道該怎麼做

    4. 是的,我藉由看老師的文章,我知道對於nodejs接收line的訊息還有回覆知道該怎麼做,但是我還是搞不懂我該怎麼去將arduino與nodejs連結,並且讓arduino將資料給nodejs

    5. 這系列貼文,本來就是補充文件,不是寫給沒有程式設計基礎的人看的,我也很傷腦筋。

      thanks,
      jeffrey

  20. 老師我訪問Heroku的HTTP請求回傳值是-1,好像是訪問被deny掉,不太知道要怎麼解決

  21. http.begin(“你的應用程式名稱.herokuapp.com”, 80, “/btn?key=你的密碼&id=wash_dish”);
    老師請問一下這只要網址就可以了嗎?還是一定要設密碼

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top