Blog Cover Image

Inspire you to have New thinking, Walk out your unique Road.

有的時候,你無意間遇到的一些故事,會激發你的靈感,改變你的想法,接下來你會用與之前全然不同的觀念去創造屬於你獨特的故事。

Sign @MinaYu.

[IoT物聯網應用] 太陽能案場監控系統架構與裝置介紹 | 帶您一窺IoT應用結合太陽能案場感測器的神秘面貌 | 透過一頁式網站掌控全台的太陽能廠!

Posted on

太陽能監控平台是我在上一家公司做的第二個專案/產品,在上一家公司的職涯生活,約有前1/3的時間在參與實作路燈的專案。然後之後的2/3生活都專注在太陽能產業軟體開發應用。

陸陸續續做了兩三個和太陽能能源相關的專案及產品,在這段職涯中,我擁有了許多酸甜苦辣的回憶,包括在路燈專案後的程式能力開始大幅成長。能力成長了,責任也變重了,所需要負責的事情也變多了,漸漸成長為一個獨當一面且有深度的人。

在這篇文章中,我只會介紹與太陽能監控平台與資料數據分析相關的經驗分享,其他一些比較小的專案就不列於此。

當時有參與實作太陽能監控相關專案的,除了 太陽能監控平台 之外,後來還獨立開發一個效能比較高的數據收集程式,用了比較深的技術跟較精簡的程式碼。


介紹 | 緣起

2020年5月,路燈專案確定暫時中止開發時程,下一個案子是決定和同層樓的太陽能維運及業務部門合作,開發一個一頁式太陽能監控平台,然後掛在大電視上供人觀看。

起源其實是同時有另外兩家太陽能監控公司在實作太陽能監控平台,且其中一家公司的專案目前就擺在電視上。但當時的主管跟其他部門的主管希望製作網站的掌控權由我方掌控,因此在路燈專案暫時終止後,我們主管跟專家們就希望透過我們開發團隊的力量來開發一個自己製作的太陽能監控網站平台。

而這次是真的開始有在和IoT裝置的即時巨量資料奮鬥,真的有來自120多個遍佈台灣的太陽能案場,共計1000多個太陽能感測器每兩分鐘回傳即時資料。所以開發出來的後端程式需要能夠乘載這樣的巨量數據流動。

短時間的目標是能夠做出取代電視上別家公司製作的一頁式監控網站。也就是說首要任務是先透過後端接收巨量資料,處理,計算並分析出來的數據,整合至一頁式網站,然後可以放在電視上,讓眾人一目瞭然目前全台灣太陽能案場的即時狀況。

這個網站不只是提供監控即時狀況,太陽能能源研究的學者或專家也能透過這個網站呈現的各個數據來檢視是否有發電效率低下或異常的狀態。而太陽能案場維運人員也能夠透過網站上的數據即時得知目前有無設備異常或損壞。


而中後期計畫就會是將原本一頁式網站擴展到一個管理網站。

會具備智能分析及深度分析的功能,提供報表及計算更深層數據的功能。而維運方面則是期望能透過軟體的條件判斷,將設備異常的感測器與太陽能案場裝置自動化開啟成報修單,開發新的報修功能,能讓廠商及維運人員合作修復損壞裝置。

深度知識方面,當初還研究到需要計算變流器的傾斜角度,搭配一日即時太陽日射角度來計算最大效率發電量。


IoT裝置有趣的是,裝置由於會座落於各種戶外地點,極為不穩定,聽主管說當時有著裝置泡在水裡,有的經過日曬雨打,有的被有心人士破壞或偷竊及轉賣,一個工業級的裝置也花費不少金錢製作與購買,所以能夠實作與IoT相關裝置的軟體,已經是很新奇有趣也難得的體驗了。

也由於極其不穩定,所以必須要設計更多類似解決時間差訊息過濾訊息遺失重補資料重新計算異地備援等其他解決方法來解決更多導致數據會有誤差的問題。

在這個產品,可說是學習到非常多,技術大幅成長,太陽能相關知識,軟體開發相關知識及許多商業價值的知識。

那接下來就來介紹本篇的重點: 太陽能監控平台與數據分析


目標: 一頁式整合太陽能數據監控網站

我用KeyNote 簡單化出了網站的架構,大概就是如圖,一頁式,然後放大放在電視機上。

來介紹網站中的各個部分含義,在這個網站中一共有六個部分,將從感測器收集的太陽能即時數據經過處理以及計算,最後輸出到這個網站中,一共分為:

  • 總覽 Summary
  • 參考發電量/實際發電量
  • 哪幾個太陽能廠產生最多電量 (日結算)
  • 當地溫度 (即時)
  • 營運狀態 (含六個狀態)
  • 哪一個地區的太陽能廠

由於只是demo示意圖,所以有些細節我沒有畫上去,每個數據都是每兩分鐘即時更新,下方三欄會變動,因為總共有120個太陽能案場,所以分成台灣不同的市區每10秒換地區呈現狀態。

左上方的Summary就是呈現所有太陽能廠累積加總的數據,所以像是

  • 總共累積發電量
  • 目前營運的太陽能案場
  • 目前維修的太陽能案場
  • 發電效率及達成率
  • 減碳CO2量

還有更多指標沒有在上面呈現,加總大概有8-9項加總數據。


最中間的參考發電量及實際發電量看起來只有三欄指標分別為 (日/月/年的參考/實際發電量),這一塊是整個網站中程式設計較為困難,計算上也較為困難的部分。

參考發電量: 是要經過一套數學公式將所有每兩分鐘的累加變流器數據加上每兩分鐘即時的日射數值及即時的溫度來去計算出來。

實際發電量: 就是計算目前實際的發電量。

還有一項指標是達成率,就是左邊%數的資訊,基本上就是 實際發電量 / 參考發電量 的百分比,就是一個計算出來的指標,顯示目前實際發電量發電達成了多少參考發電量。

這部分數據困難的是需要即時的資料外,還需要從每天早上5點太陽能廠開機開始的數據一直累積到即時的數據,所以必須從早上第一筆資料開始累計加總跟計算,漏了一筆就會有誤。

所以在規劃上需要做很多的防範措施以免萬一遺失資料,需要設計模擬推算出的資料取代為遺失的資料並標記為遺失,然後透過晚上回補資料的機制將遺失的資料補回。


右上方則是將當日發電量的太陽能廠由高至低排列(正確來說應該是按縣市的太陽能廠加總去比較)


下方的三欄會一起跳動,他們代表的是

左: 某個縣市的即時天氣 中: 該縣市的所有太陽能案場即時狀態(有六個狀態,像是溫度異常或者設備損壞) 右: 用地圖標示目前在哪個縣市


總共大約是用了2-3個月的時間將這個一頁式監控網站(Dashboard)給做出來,因為已經有別的公司做出正式運行的版本,所以大部分的時間都花在和正式運行版本對照,每個數字都需要準確,每個公式都要正確無誤,也就是說如果該公司私下有訂定一些規則去濾掉不規則的值或者一些其他的規則跟條件,我們是不知道,且要想辦法數字跟正式運行的網站一樣。


太陽能案場內部裝置資訊

其實這個部分是我最後才寫的,因為對於太陽能廠內部架構,一直到快離職前都還沒接觸到太多,畢竟在後端軟體工作的我們,只需要有個初步的概念,知道哪些裝置及感測器,它的功用大概是什麼,他會怎麼傳訊息跟傳什麼訊息給我們,大約略知即可。

雖然可能我畫的圖並不是最正確的,畢竟不是承包商也不是實際赴當地架設的人,但還是稍微簡略化一下架構並作說明。

這個是我目前腦海內的太陽能廠裝置佈置圖,我知道漏了很多很重要的其他裝置,但後端的程式大部分只會接收來自這些裝置的訊息。

後端的程式透過MQTT (本專案是透過api取得資訊,這個下面內容會描述),取得的裝置內容為:

  • 變流器 Inverter
  • 溫度計 Thermometer
  • 日射計 Radiator
  • 風向儀 Anemoscope
  • 風速計 Anemometer

之所以會寫太陽能板 Panel,是想示意説,真正的太陽能板是接在變流器後,而且中間還有其他裝置跟較複雜的串並關聯,不過這在不多做討論。

變流器主要會傳遞發電量及和電能相關的參數,是計算即時發電量,累積發電量及其他重要與發電相關的資訊

溫度計則是回報當地太陽能廠目前的環境溫度,只會有一個,代表當地的環境溫度,可提供搭配計算參考/預期發電量

日射計則是回傳日射量,也只會有一個去測量太陽照射的量 (通常早上會比較少,直到中午跟下午,日射量可能會破萬,然後傍晚漸漸降低),可提供搭配計算參考/預期發電量。開機時會傳遞不正常值,若發現不正常值需要濾掉。

風向儀風速計目前還不了解參數內容,因為這兩個是非常後期加進來的裝置,直到我們要開始動工納入計算前,公司政策就改變了(這個下面也會提及),主要回傳內容應該是與當地的風速及風向相關。

太陽能板視擺放位置可能會有角度問題,像是傾斜度,所以其實在當時的未來規劃是希望能紀錄細項到太陽能板的傾斜角度,然後搭配溫度跟日射量還有變流器去計算出準確的參考/預期發電量,可以檢討為什麼實際發電無法達標。

最後雖然跟裝置無關,但是在當時的未來規劃中,也許要去即時計算太陽的仰角與傾角角度搭配其他數據去做計算。

總之無論是太陽能廠與太陽能能源相關的數據都是另外一門學問,而作為開發團隊的我們就是努力和專家了解這些資訊,盡量做出準確以及能夠協助使用者的好產品/專案。


軟體架構

看起來畫得有點複雜,讓我來解釋一下

原則上最終目標都是產出上面提及的Dashboard,所以Front-end的部分就是Dashboard呈現的外觀,而後端的部分就是將螢幕上面所有的數據計算與產出給前端,也就是 Main Process ProgramIoT Devices的部分。


前端網頁如何取得資訊?

原則上這個Dashboard上的數據是每兩分鐘更新的即時數據,所以會有兩個部分維持能讓前端能維持取得最新的資訊。

  • 從後端網站取得

若使用者有

  1. 剛打開網頁
  2. 重整網頁

那麼最新資訊就會是由前端去送request請求給後端,取得頁面上所有的即時資訊。

但問題既然是Dashboard,他大部分的時間就會是一直開著網站,不會有任何重整或重開的動作。

這時候就需要規劃另外一種方法來取得最新資訊。


  • 訂閱MQTT,即時接收後端每兩分鐘剛計算好的數據,透過MQTT傳給前端

不只後端,前端的部分也有MQTT技術,因此為了要維持前端的頁面都是最新資訊,我們請前端訂閱產出結果的頻道,然後後端的程式則是每兩分鐘從感測器收集資訊,計算後將結果發送至頻道,這麼一來前端網頁就能即時獲得資訊。


後端網站 (Back-end Web)

在這個專案中,後端網站的部分只有簡單的一個功能,就是將計算好的即時資訊提供給前端,所以只開一個api,而由另外一隻程式處理與計算的結果會存在Redis中,這隻api的功能就是從Redis讀取計算好的即時結果,然後回傳給前端網頁。

這麼一來無論是剛開頁面或刷新頁面,都能即時取到最新資訊。


即時處理數據 (Data Processor)

即時處理數據的程式,是這個Dashboard主要的後端程式開發,我們先稱呼他為資料處理程式,簡單來說就是每兩分鐘會驅動一次該程式,他會接收每個太陽能案場的感測器即時資料,處理並計算後,發送即時資訊到MQTT的指定頻道,提供前端網頁即時資訊,而另外則是將結果存入Redis,讓後端網站可以透過讀取Redis的結果,提供最新資料給前端。

當然所有的處理與計算的結果或者原始資料都會紀錄於資料庫。


接著來看看實際程式實作的架構圖,也就是說這個Data Processor的程式實作邏輯:

  • 先取得所有太陽能案場以及旗下的感測器裝置資訊
  • 利用裝置資訊取得即時的感測器資料 (稍後說明)
  • 處理資料
    • 擷取重要資訊與數據
    • 單位換算
    • 去除不正常數據
  • 計算資料
    • 統計無反應,損毀或不正常數據的感測器,並計算六種錯誤狀態
    • 計算總發電量,累計發電,發電排名及CO2減碳量資訊
    • 計算預期/參考的發電量,實際發電量與達成率
  • 儲存
    • 將原始資料及計算後的數據儲存於資料庫
    • 將初始化值,需更新的值及最終計算結果儲存於Redis
  • 透過MQTT發布給前端

取得即時資訊

看著架構圖跟描述會覺得有點奇怪,怎麼太陽能案場的感測器不是透過MQTT即時接收到後端程式?

在這邊說明一下,一個比較特別的點,由於上面有提及公司先前已經有委託其他公司協助製作監控管理平台,也就是說已經和某家公司協調,由他們包辦太陽能場,地方所有的感測器佈置以及接收資料與儲存資料,因此我們沒有辦法去設定感測器傳資料的設定,也無法知道MQTT的頻道,都屬另外一間公司的商業機密。

但可以接受我方透過對方的提供的後端api取得資料,所以算是二手資料,就是最開始已經是對方先接收處理過了,才會讓我們能夠過api取得資料,約莫會延遲2-4分鐘的資料。

也由於對方的後端程式設計,我方若需要透過api取得資料時,需要以太陽能廠資訊 + 裝置名稱 + 取得時間 做為參數,因此才會有第一步取得裝置資訊


第一步驟就是先取得太陽能廠及其每個感測器的資訊,由於程式是每兩分鐘排程執行一次,總不可能每次都去資料庫要一次資料,再加上經過討論,裝置極少機率會需要更換或替補,不太會常更動,所以在裝置資訊的設計,我們將所有的裝置資訊儲存於Redis中,除非有新增刪除裝置,才會重新將資訊輸入Redis,這麼一來每兩分鐘需要取得裝置資訊的動作也就不會這麼頻繁的對資料庫做操作。

第二個比較複雜一點,由於上述提及資料是在別的公司的資料庫中,需要透過api去取得,而需要用資料時間做為參數,來取得指定時間的感測器即時資料,由於怕資料過於龐大,所以一次只開放取30分鐘的資料。參數規格會是2021 08/22 08:02 ~ 2021 08/22 08:32,如果你以為這麼簡單的話,就太天真了!

因為必須考量到可能會有感測器的資料是遺失的 (而且常常發生類似停機或遺失的狀況),所以在設計取資料的時間區段,就不會是以當下的時間加減30分鐘去取。我們會為每個感測器加上最新資料的時間然後存儲於Redis,這是模擬格式:

solar:site:<site_id>:<sensor_id> : 1629616967 (換成UNIX時間,因為Redis不能存Datetime)

而依據就是取得資料時,會取得30分鐘資料:

2021 08/22 07:22 ~ 2021 08/22 07:52

這只是取得的指定期間,實際上該感測器最新的資料時間可能只會到 07:42,那就需要紀錄目前該感測器的資訊只取到 07:42,然後下一次要透過api取得資料時,就會變成是

2021 08/22 07:42 ~ 2021 08/22 08:12

07:42,最新資料來往後算30分鐘,而在Redis中,每個感測器的最新資料時間也不會相同,因為會有些停機或者遺失資料的狀態發生,這樣也方便計算錯誤狀態


除此之外,由於取到的資料是每30分鐘計算,也要特別檢查這30分鐘中,有沒有遺失的資料,比方說:

2021 08/22 07:42 2021 08/22 07:46 2021 08/22 07:48 2021 08/22 07:50

少了 07:44 的資料,這個時候就要補上一筆空的資料,並標記為遺失資料,等待晚上補資料的程式運作,再根據遺失的資料再去api取資料。


處理與計算

這部分包含

  • 擷取重要資訊與數據
  • 單位換算
  • 去除不正常數據

取到的感測器訊息會是含有許多不同的參數,但有時候不需要這麼多參數,所以只取得我們需要的數據,然後做單位換算,或者是合成下一步計算需要的數據。

最後就是偵測一些不正常的數據,比方說早上6~9點的日射量不會 >15000,超過就需要懷疑是否裝置問題,還有就是環境溫度不得 >39,過高也有問題。


計算數據的話,也沒什麼問題,就是計算類似

  • 錯誤狀態
  • 總體數據
  • 排名
  • 預期達成數據 (參考發電)

其中比較難算的是 參考發電,畢竟需要各個感測器正常運作的數值加上溫度及日射計的正常運作,且從早上第一筆開始累計,也就是說若有遺失或損毀的部分,我們的程式設計機制就是將前一筆資料作為依據,複製到後一筆做為參考,並把這筆資料標記為遺失待補。

也就是說:

07:42 早上日射量為 231 07:44213 07:46 的當下缺了資料,那就把上一筆的 213作為這兩分鐘偵測到的日射量。


儲存與發佈

  • 儲存
    • 將原始資料及計算後的數據儲存於資料庫
    • 將初始化值,需更新的值及最終計算結果儲存於Redis
  • 透過MQTT發布給前端

原則上沒什麼太大的問題,就是照這樣的步驟去實作


回補資料 (Data Patcher)

由於IoT裝置會時常發現不穩定的狀況,所以有時候資料會遺失或者需要停機維修,這時候後端的平台會接收不到資訊,而造成計算出來的數據與真實的狀況可能有差異。

為了盡量能夠貼近更真實的數據,我們也同樣實作了一個補資料的程式(Data Patcher),在晚上凌晨時啟動,用整個晚上的時間重新取得過去遺失的資料,然後重新計算像是年/月累積參考發電或實際發電這種需要累加的數據,再更新回資料庫。


所以架構圖會如上方,晚上太陽能廠沒有在運作,人們也需要休息,所以前端網頁不需要更新資訊。

程式步驟如下:

  • 從資料庫取得被標記為遺失的資料
  • 透過資料的裝置id,找到 裝置資訊
  • 組成 裝置資訊 + 遺失時間,並向api取資料
  • 處理資料
  • 重新計算資料 (像是那種累積性質的資料,修正資料正確性)
  • 儲存回資料庫跟更新Redis

補資料跟早上取資料的程式邏輯差不多,只是欲取的資料從資料庫中被標記為遺失的資料為主。

計算的部分,因為只要有資料補回,就會影響像是:

  • 年參考發電量
  • 月參考發電量
  • 總實際發電量

類似這類型的數據指標,而且別忘了剛剛有說過像是參考發電的數據,必須是該太陽能廠所有的變流器 + 日射計 + 溫度計,從早上開機開始一直累積。

所以只要一有補任何的資料,就要當日全部從凌晨開機的時間點,重算到傍晚關機時間,然後再將每天的數據加總才會是正確的月跟年參考發電,取資料加上重算資料需要一整個晚上的時間也不為過。


使用到的技術

對比於上一個路燈的專案,比較中規中矩適合初階者練習,在太陽能監控平台這個專案,基於有先前路燈的經驗,規劃專案的能力更是提升許多,尤其是要規劃程式的架構跟功能分割,已經有先前的能力,在這個專案中,更能熟練的思考。

相比於上一個路燈專案是學會用物件導向實作專案,在此專案最大的進步應該就是終於了解資料結構跟如何運用於專案中增加效能跟讓功能精緻化。

學到的技術包括像是用Redis,Queue資料結構跟字典Dictionary暫存來儲存一些資訊,提高機動性,效能跟減少大量對資料庫的操作動作。

再來在之後重新做了一個資料收集的程式,也學習到利用Async跟Thread等模式來提高收集資料的效能。

除此之外,除了對MQTT較熟練之外,還初次接觸到了感測器傳來貼近機械語言的訊息,需要做切割跟翻譯,才能讓後續的程式做處理。

學習到跟技術無關的知識則是有請太陽能能源專家讓我們學習到整個太陽能廠的運作,還有有關於太陽能能源的知識,像是如何發電,與太陽的傾斜角度相關,相關的太陽能能源公式,都有學習到。

在這整個太陽能專案中,我認為最主要進步的是那些抽象與邏輯的思維模式,像是

  • 學會繪製流程圖
  • 學會規劃程式架構
  • 學會去發想一些後續的防範機制
  • 學會去針對商業邏輯的部份想出優化跟解決機制

而我也認為,後端工程師的後續成長,比較像是偏抽象與邏輯思維的鍛鍊,簡單來說就是

怎麼將生活化或商業價值邏輯化,然後實作出來

至於用什麼程式語言或者用什麼套件,都是基本的配備,因為只要邏輯對了,用什麼程式語言或套件都能建構出專案/產品。


其他

特殊的資料庫設計

在實際的太陽能廠,是有很多個變流器,每個變流器都會記錄他的累積總發電量,但是難免會遇到需要將變流器換掉的機會,新的變流器會將舊的變流器的發電量承接上來,這設計應該是沒什麼問題。

但是在後端程式的資料庫,新的變流器跟舊的變流器理論上是屬於 兩個不同的變流器id,他在太陽能廠的位置是同一個,而且替換時,廠商會直接累計舊的發電量。

不過在程式上,就會是兩個變流器id,分別的兩個累積量,因此在設計上會需要有一個抽象的思考,本來的思考層面是停在以裝置id做單位,只收集各個id的資料,但因為要顧及會有更換裝置,還是需要累積發電量這樣的問題。

因此在資料庫的設計上,會多一個抽象的資料表(Table),我們以太陽能廠內部架構的思維去設計,也就是說假設內部架構代表D1的變流器DPX0002壞掉了,換了一台DPX3302,也是在同個D1區做互換,而累積的發電量就記在D1這一筆資料中,所以:

在抽象思維的資料表就會記為

id place accumulate_power
1    D1        33402

然後會有另外一個紀錄裝置的資料表

id device_id place_id accumulate_power
1   DPX0002      D1         30202
2   DPX3302      D1          3200

所以類似這類型的問題,在這次的太陽能專案會時常遇到。


太陽能二版資料收集程式

由於即時資料是每兩分鐘一次,所以照道理來說,我們必須要在2分鐘內做到

  • 取資料
  • 處理
  • 計算

通常會在取資料的部分花費比較多的時間,因為是使用了單一Thread機制,也就是說

總共有116太陽能場共千多個感測器,然後初版的資料收集程式是用可愛的for迴圈,從第一個案場開始取,開始丟對方公司的api,取完所有的太陽能廠資料後,在進入到處理的部分。

有時候整個程式執行下來,會逼近1分30秒,如果遇到一些網路不佳的問題,可能會有遺失或delay的問題。


因此,我做了第二版的資料收集程式,其實當初也是請求主管能讓我有個專案練習多執行緒XD,因為我想學,所以這個程式就是拿來學習的成果。

基本上,這個程式在實作時,有學習到了怎麼使用Python去實作多執行緒Async 的概念,最終完成的程式是使用Async去實作,也就是說盤點116太陽能場,然後分成為116個task任務,並使用Async的方式分別去取api資料,然後處理,等到最後都彙整完畢在做計算。

改良後的資料數據程式速度大約為15~30秒左右,相比第一版的1分30秒已經快許多,快到我都在懷疑他到底有沒有取到資料XD


自己公司去承包太陽能廠佈置與數據

當初製作這個一頁式監控網站時,其實就是公司希望能夠用自己的力量掌控整個太陽能廠的佈置與監控。

所以其實在我在職時比較靠後面的時間,其中一個太陽能廠就是自己包辦。

雖然我沒有實際參與在其中,但是我看到我的主管跟另外一個能源博士每天都在比價不同的變流器廠牌,然後我主管還要和硬體工程師去合作撰寫軟體然後嵌入感測器中,所有的事情都是第一次遇到也是第一次包辦,所以看得出來他們非常的疲累與急迫,上層給的人又非常少。

其中一個篇軟體方面遇到的問題就是,數據真的是從MQTT傳來的,但是由於沒有太多時間做溝通,所以硬體工程師就直接寫成都是01且用一些特殊符號做區段,所以後續再接資料的時候,必須依據從第幾個位元到第幾個位元代表發電量,類似這樣的邏輯去處理從MQTT收到的資訊。


老實說,我敢相信如果公司再多給一些人力,一定能夠將承包太陽能廠的佈置跟監控平台的工作給整個包下來並成立部門持續運作新能源廠。

但是試問哪個老闆願意這樣呢?

因為要知道光是蓋一個太陽能廠就直接扔掉了3-4億,要靠發電來賺錢,通常需要運作到第七年之後才會陸續賺錢,無法立即看到價值,又毫無效率賺錢,哪個老闆想做這種賠錢的生意呢?

為了國家發展?慈善?


所以,在新官上任後,決策轉彎後,監控平台建置的軟體部門也轉型了,不再做開發了,太陽能廠也從原本想自己承包,改為由外部承包然後把太陽能廠當作商品賣掉,而不是透過後續發電來賺錢。

我仍然相信能源是極其重要,尤其是再生能源,既然每天都會有太陽,利用太陽發電後,供電給人民生活是一個很好選擇,但是很少人知道背後的建置需要花費高額金錢跟多少人力以及帶來的污染都無法細數。