ทุกครั้งที่ได้รับค่าไฟฟ้าและค่าน้ำ ก็ต้องแปลกใจ ครอบครัวของฉันใช้ไฟฟ้าเยอะขนาดนี้เลยหรือ? ใช่ ห้องน้ำมีพื้นระบบทำความร้อนและหม้อต้มน้ำ แต่ไม่ได้จุดไฟตลอดเวลา ดูเหมือนเราจะประหยัดน้ำด้วย (แม้ว่าเราจะชอบเล่นน้ำในห้องน้ำก็ตาม) เมื่อหลายปีก่อนฉันแล้ว
ฉันเพิ่งเปลี่ยนมาใช้ Home Assistant เป็นระบบบ้านอัจฉริยะของฉัน สาเหตุหนึ่งก็คือโอกาสในการจัดระเบียบการรวบรวมข้อมูลจำนวนมากพร้อมความสามารถในการสร้างกราฟประเภทต่างๆ ได้อย่างสะดวก
ข้อมูลที่อธิบายในบทความนี้ไม่ใช่เรื่องใหม่มีการอธิบายสิ่งต่าง ๆ เหล่านี้ทั้งหมดภายใต้ซอสต่าง ๆ บนอินเทอร์เน็ตแล้ว แต่แต่ละบทความมักจะอธิบายแนวทางหรือแง่มุมเดียวเท่านั้น ฉันต้องเปรียบเทียบวิธีการเหล่านี้ทั้งหมดและเลือกวิธีที่เหมาะสมที่สุดด้วยตัวเอง บทความนี้ไม่ได้ให้ข้อมูลที่ครอบคลุมเกี่ยวกับการรวบรวมข้อมูล แต่เป็นบทสรุปว่าฉันทำอย่างไร ดังนั้นจึงยินดีรับคำวิจารณ์และข้อเสนอแนะที่สร้างสรรค์เพื่อการปรับปรุง
คำแถลงปัญหา
ดังนั้น เป้าหมายของการออกกำลังกายวันนี้คือการได้กราฟปริมาณการใช้น้ำและไฟฟ้าที่สวยงาม:
- รายชั่วโมงเป็นเวลา 2 วัน
- ทุกวันเป็นเวลา 2 สัปดาห์
- (ไม่บังคับ) รายสัปดาห์และรายเดือน
มีปัญหาบางประการในเรื่องนี้:
- ส่วนประกอบของแผนภูมิมาตรฐานมักจะค่อนข้างแย่ อย่างดีที่สุด คุณสามารถสร้างกราฟเส้นทีละจุดได้
หากคุณพิจารณาให้ดีพอ คุณจะพบส่วนประกอบของบริษัทอื่นที่ขยายขีดความสามารถของแผนภูมิมาตรฐานได้ โดยหลักการแล้วสำหรับผู้ช่วยที่บ้านนี่เป็นองค์ประกอบที่ดีและสวยงาม
การ์ดมินิกราฟ แต่ก็มีข้อจำกัดบ้างเช่นกัน:- เป็นการยากที่จะตั้งค่าพารามิเตอร์ของแผนภูมิแท่งในช่วงเวลาขนาดใหญ่ (ความกว้างของแท่งถูกกำหนดเป็นเศษส่วนของชั่วโมง ซึ่งหมายความว่าช่วงเวลาที่นานกว่าหนึ่งชั่วโมงจะถูกกำหนดเป็นเลขเศษส่วน)
- คุณไม่สามารถเพิ่มเอนทิตีที่แตกต่างกันลงในกราฟเดียวได้ (เช่น อุณหภูมิและความชื้น หรือรวมกราฟแท่งเข้ากับเส้น)
- ผู้ช่วยที่บ้านไม่เพียงแต่ใช้ฐานข้อมูล SQLite ดั้งเดิมที่สุดตามค่าเริ่มต้น (และฉันซึ่งเป็นช่างซ่อมบำรุงไม่สามารถจัดการการติดตั้ง MySQL หรือ Postgres ได้) แต่ข้อมูลไม่ได้ถูกจัดเก็บด้วยวิธีที่เหมาะสมที่สุด ตัวอย่างเช่น ทุกครั้งที่คุณเปลี่ยนพารามิเตอร์ดิจิทัลที่เล็กที่สุดของพารามิเตอร์ json ขนาดใหญ่ประมาณหนึ่งกิโลไบต์จะถูกเขียนลงในฐานข้อมูล
{"entity_id": "sensor.water_cold_hourly", "old_state": {"entity_id": "sensor.water_cold_hourly", "state": "3", "attributes": {"source": "sensor.water_meter_cold", "status": "collecting", "last_period": "29", "last_reset": "2020-02-23T21:00:00.022246+02:00", "meter_period": "hourly", "unit_of_measurement": "l", "friendly_name": "water_cold_hourly", "icon": "mdi:counter"}, "last_changed": "2020-02-23T19:05:06.897604+00:00", "last_updated": "2020-02-23T19:05:06.897604+00:00", "context": {"id": "aafc8ca305ba4e49ad4c97f0eddd8893", "parent_id": null, "user_id": null}}, "new_state": {"entity_id": "sensor.water_cold_hourly", "state": "4", "attributes": {"source": "sensor.water_meter_cold", "status": "collecting", "last_period": "29", "last_reset": "2020-02-23T21:00:00.022246+02:00", "meter_period": "hourly", "unit_of_measurement": "l", "friendly_name": "water_cold_hourly", "icon": "mdi:counter"}, "last_changed": "2020-02-23T19:11:11.251545+00:00", "last_updated": "2020-02-23T19:11:11.251545+00:00", "context": {"id": "0de64b8af6f14bb9a419dcf3b200ef56", "parent_id": null, "user_id": null}}}
ฉันมีเซ็นเซอร์ค่อนข้างมาก (เซ็นเซอร์อุณหภูมิในแต่ละห้อง มิเตอร์น้ำและไฟฟ้า) และบางตัวก็สร้างข้อมูลค่อนข้างมากด้วย ตัวอย่างเช่น มิเตอร์ไฟฟ้า SDM220 เพียงอย่างเดียวสร้างค่าประมาณหนึ่งโหลทุกๆ 10-15 วินาที และฉันต้องการติดตั้งมิเตอร์ดังกล่าวประมาณ 8 เมตร นอกจากนี้ยังมีพารามิเตอร์อีกมากมายที่คำนวณจากเซ็นเซอร์อื่น ๆ ที่. ค่าทั้งหมดเหล่านี้สามารถขยายฐานข้อมูลได้อย่างง่ายดาย 100-200 MB ต่อวัน ในหนึ่งสัปดาห์ระบบจะแทบจะไม่เคลื่อนไหวและในหนึ่งเดือนแฟลชไดรฟ์ก็จะตาย (ในกรณีของการติดตั้งผู้ช่วยที่บ้านทั่วไปบน Raspberry PI) และการจัดเก็บข้อมูลตลอดทั้งปีก็ไม่มีปัญหา
- หากคุณโชคดี มิเตอร์ของคุณสามารถนับการบริโภคได้เอง คุณสามารถหันไปที่มิเตอร์ได้ตลอดเวลาและถามว่ามูลค่าการบริโภคสะสมคือเวลาใด ตามกฎแล้ว มิเตอร์ไฟฟ้าทั้งหมดที่มีอินเทอร์เฟซดิจิทัล (RS232/RS485/Modbus/Zigbee) จะให้โอกาสนี้
จะแย่กว่านั้นหากอุปกรณ์สามารถวัดพารามิเตอร์บางอย่างที่เกิดขึ้นในขณะนั้นได้ (เช่น กำลังหรือกระแสที่เกิดขึ้นในขณะนั้น) หรือเพียงแค่สร้างพัลส์ทุกๆ X วัตต์-ชั่วโมงหรือลิตร จากนั้นคุณต้องพิจารณาว่าจะบูรณาการอย่างไรและอย่างไร และจะสะสมมูลค่าได้ที่ไหน มีความเสี่ยงที่จะพลาดรายงานถัดไปไม่ว่าด้วยเหตุผลใดก็ตาม และความถูกต้องของระบบโดยรวมทำให้เกิดคำถาม แน่นอนคุณสามารถมอบความไว้วางใจทั้งหมดนี้ให้กับระบบสมาร์ทโฮมเช่นผู้ช่วยในบ้านได้ แต่ไม่มีใครยกเลิกประเด็นเกี่ยวกับจำนวนบันทึกในฐานข้อมูลและเป็นไปไม่ได้ที่จะสำรวจเซ็นเซอร์มากกว่าหนึ่งครั้งต่อวินาที (a ข้อจำกัดของสถาปัตยกรรมผู้ช่วยในบ้าน)
แนวทางที่ 1
ขั้นแรก เรามาดูกันว่าผู้ช่วยประจำบ้านจะให้อะไรบ้างเมื่อแกะกล่อง การวัดปริมาณการใช้ในช่วงเวลาหนึ่งเป็นฟังก์ชันที่เป็นที่ต้องการอย่างมาก แน่นอนว่ามีการใช้งานมานานแล้วในรูปแบบของส่วนประกอบพิเศษ - utility_meter
สาระสำคัญของส่วนประกอบคือสร้างตัวแปร current_accumulated_value ภายในและรีเซ็ตหลังจากระยะเวลาที่กำหนด (ชั่วโมง/สัปดาห์/เดือน) ส่วนประกอบจะตรวจสอบตัวแปรอินพุตเอง (ค่าของเซ็นเซอร์บางตัว) สมัครรับการเปลี่ยนแปลงของค่า - คุณเพิ่งได้ผลลัพธ์ที่เสร็จสิ้น สิ่งนี้อธิบายไว้เพียงไม่กี่บรรทัดในไฟล์กำหนดค่า
utility_meter:
water_cold_hour_um:
source: sensor.water_meter_cold
cycle: hourly
water_cold_day_um:
source: sensor.water_meter_cold
cycle: daily
ในที่นี้ sensor.water_meter_cold คือค่ามิเตอร์ปัจจุบันในหน่วยลิตรที่ฉันได้รับ
รหัสสำหรับแผนภูมิรายชั่วโมงและรายวันสำหรับ lovelace-UI มีลักษณะดังนี้:
- type: history-graph
title: 'Hourly water consumption using vars'
hours_to_show: 48
entities:
- sensor.water_hour
- type: history-graph
title: 'Daily water consumption using vars'
hours_to_show: 360
entities:
- sensor.water_day
จริงๆ แล้ว ปัญหาของแนวทางนี้อยู่ที่อัลกอริทึมนี้ ตามที่ฉันได้กล่าวไปแล้ว สำหรับแต่ละค่าอินพุต (การอ่านมิเตอร์ปัจจุบันสำหรับแต่ละลิตรถัดไป) บันทึก 1kb จะถูกสร้างขึ้นในฐานข้อมูล มิเตอร์อรรถประโยชน์แต่ละเครื่องยังสร้างค่าใหม่ซึ่งจะถูกเพิ่มเข้าไปในฐานด้วย หากฉันต้องการรวบรวมการอ่านค่ารายชั่วโมง/รายวัน/รายสัปดาห์/รายเดือน และสำหรับเครื่องสูบน้ำหลายเครื่อง และเพิ่มมิเตอร์ไฟฟ้าหนึ่งชุด นั่นจะเป็นข้อมูลจำนวนมาก แม่นยำยิ่งขึ้นคือไม่มีข้อมูลมากนัก แต่เนื่องจากผู้ช่วยที่บ้านเขียนข้อมูลที่ไม่จำเป็นจำนวนมากลงในฐานข้อมูล ขนาดของฐานข้อมูลจึงเพิ่มขึ้นอย่างก้าวกระโดด ฉันกลัวที่จะประมาณขนาดของฐานสำหรับแผนภูมิรายสัปดาห์และรายเดือนด้วยซ้ำ
นอกจากนี้มิเตอร์ยูทิลิตี้เองก็ไม่สามารถแก้ปัญหาได้ กราฟของค่าที่สร้างโดยมิเตอร์อรรถประโยชน์เป็นฟังก์ชันที่เพิ่มขึ้นซ้ำซากซึ่งจะรีเซ็ตเป็น 0 ทุกชั่วโมง เราต้องการแผนภูมิปริมาณการใช้ที่ผู้ใช้เข้าใจได้ โดยแสดงจำนวนลิตรที่ใช้ไปในช่วงเวลานั้น องค์ประกอบกราฟประวัติมาตรฐานไม่สามารถทำได้ แต่ส่วนประกอบภายนอกมินิกราฟการ์ดสามารถช่วยเราได้
นี่คือรหัสการ์ดสำหรับ lovelace-UI:
- aggregate_func: max
entities:
- color: var(--primary-color)
entity: sensor.water_cold_hour_um
group_by: hour
hours_to_show: 48
name: "Hourly water consumption aggregated by utility meter"
points_per_hour: 1
show:
graph: bar
type: 'custom:mini-graph-card'
นอกเหนือจากการตั้งค่ามาตรฐาน เช่น ชื่อเซ็นเซอร์ ประเภทกราฟ สี (ฉันไม่ชอบสีส้มมาตรฐาน) การตั้งค่า 3 รายการที่สำคัญที่ควรทราบ:
- group_by:hour — กราฟจะถูกสร้างขึ้นโดยมีแท่งจัดชิดกับจุดเริ่มต้นของชั่วโมง
- point_per_hour: 1 - หนึ่งบาร์ต่อชั่วโมง
- และที่สำคัญที่สุดคือ integrated_func: max - รับค่าสูงสุดภายในแต่ละชั่วโมง พารามิเตอร์นี้เองที่เปลี่ยนกราฟฟันเลื่อยให้เป็นแท่ง
อย่าไปสนใจแถวของคอลัมน์ทางด้านซ้าย นี่เป็นลักษณะการทำงานมาตรฐานของส่วนประกอบหากไม่มีข้อมูล แต่ไม่มีข้อมูล - ฉันเปิดการรวบรวมข้อมูลมิเตอร์สาธารณูปโภคเมื่อสองสามชั่วโมงที่แล้วเพื่อประโยชน์ของบทความนี้เท่านั้น (ฉันจะอธิบายแนวทางปัจจุบันของฉันด้านล่าง)
ในภาพนี้ ฉันต้องการแสดงให้เห็นว่าบางครั้งการแสดงข้อมูลยังใช้งานได้ และแถบก็สะท้อนค่าที่ถูกต้องจริงๆ แต่นั่นไม่ใช่ทั้งหมด ด้วยเหตุผลบางประการ คอลัมน์ที่เลือกในช่วงเวลาตั้งแต่ 11 น. ถึง 12 น. จะแสดง 19 ลิตร แม้ว่าบนกราฟฟันจะสูงขึ้นเล็กน้อยในช่วงเวลาเดียวกันจากเซ็นเซอร์เดียวกันเราจะเห็นว่าสิ้นเปลือง 62 ลิตร อาจมีแมลงหรือมือคดเคี้ยว แต่ฉันยังไม่เข้าใจว่าเหตุใดข้อมูลทางด้านขวาจึงขาด - การบริโภคเป็นเรื่องปกติซึ่งมองเห็นได้จากกราฟฟันด้วย
โดยทั่วไปแล้ว ฉันไม่สามารถบรรลุความน่าเชื่อถือของแนวทางนี้ได้ - กราฟมักจะแสดงความบาปบางประเภทเสมอ
รหัสที่คล้ายกันสำหรับเซ็นเซอร์กลางวัน
- aggregate_func: max
entities:
- color: var(--primary-color)
entity: sensor.water_cold_day_um
group_by: interval
hours_to_show: 360
name: "Daily water consumption aggregated by utility meter"
points_per_hour: 0.0416666666
show:
graph: bar
type: 'custom:mini-graph-card'
โปรดทราบว่าพารามิเตอร์ group_by ถูกตั้งค่าเป็นช่วงเวลา และพารามิเตอร์ point_per_hour จะควบคุมทุกอย่าง และในนั้นก็มีปัญหาอีกประการหนึ่งกับองค์ประกอบนี้ - point_per_hour ทำงานได้ดีบนแผนภูมิหนึ่งชั่วโมงหรือน้อยกว่านั้น แต่จะแย่มากในช่วงเวลาที่มากขึ้น ดังนั้นเพื่อให้ได้หนึ่งคอลัมน์ในหนึ่งวัน ผมต้องป้อนค่า 1/24=0.04166666 ฉันไม่ได้พูดถึงแผนภูมิรายสัปดาห์และรายเดือนด้วยซ้ำ
แนวทางที่ 2
ในขณะที่ยังคงเข้าใจผู้ช่วยประจำบ้านอยู่ ฉันได้พบวิดีโอนี้:
เพื่อนคนหนึ่งรวบรวมข้อมูลการบริโภคจากซ็อกเก็ต Xiaomi หลายประเภท งานของเขาง่ายกว่าเล็กน้อย - เพียงแสดงมูลค่าการบริโภคสำหรับวันนี้ เมื่อวาน และสำหรับเดือน ไม่จำเป็นต้องมีตารางเวลา
ทิ้งการอภิปรายเกี่ยวกับการรวมค่าพลังงานทันทีด้วยตนเอง - ฉันได้เขียนไว้ข้างต้นเกี่ยวกับ "ความแม่นยำ" ของแนวทางนี้ ยังไม่ชัดเจนว่าเหตุใดเขาจึงไม่ใช้มูลค่าการบริโภคสะสมที่ร้านค้าเดียวกันรวบรวมไว้แล้ว ในความคิดของฉัน การบูรณาการภายในฮาร์ดแวร์จะทำงานได้ดีขึ้น
จากวิดีโอ เราจะนำแนวคิดของการนับการบริโภคด้วยตนเองในช่วงเวลาหนึ่งๆ ผู้ชายนับเฉพาะค่าของวันนี้และเมื่อวาน แต่เราจะไปต่อและพยายามวาดกราฟ สาระสำคัญของวิธีการที่เสนอในกรณีของฉันมีดังนี้
เรามาสร้างตัวแปร value_at_the_beginning_of_hour กัน ซึ่งเราจะบันทึกการอ่านมิเตอร์ปัจจุบัน
เมื่อใช้ตัวจับเวลา เมื่อสิ้นสุดชั่วโมง (หรือต้นชั่วโมงถัดไป) เราจะคำนวณความแตกต่างระหว่างการอ่านค่าปัจจุบันกับค่าที่เก็บไว้ตอนต้นชั่วโมง ความแตกต่างนี้จะเป็นปริมาณการใช้ชั่วโมงปัจจุบัน - เราจะบันทึกค่าลงในเซ็นเซอร์และในอนาคตเราจะสร้างกราฟตามค่านี้
คุณต้อง "รีเซ็ต" ตัวแปร value_at_beginning_of_hour ด้วยการเขียนค่าตัวนับปัจจุบันที่นั่น
ทั้งหมดนี้สามารถทำได้ผ่านผู้ช่วยที่บ้านเอง
คุณจะต้องเขียนโค้ดมากกว่าวิธีก่อนหน้าเล็กน้อย ขั้นแรก เรามาสร้าง "ตัวแปร" เดียวกันนี้กันก่อน เราไม่มีเอนทิตี "ตัวแปร" นอกกรอบ แต่เราสามารถใช้บริการของโบรกเกอร์ mqtt ได้ เราจะส่งค่าไปที่นั่นพร้อมกับแฟล็ก Keep=true ซึ่งจะบันทึกค่าภายในนายหน้า และสามารถดึงออกจากที่นั่นได้ตลอดเวลา แม้ว่าผู้ช่วยในบ้านจะรีบูทก็ตาม ฉันสร้างเคาน์เตอร์รายชั่วโมงและรายวันพร้อมกัน
- platform: mqtt
state_topic: "test/water/hour"
name: water_hour
unit_of_measurement: l
- platform: mqtt
state_topic: "test/water/hour_begin"
name: water_hour_begin
unit_of_measurement: l
- platform: mqtt
state_topic: "test/water/day"
name: water_day
unit_of_measurement: l
- platform: mqtt
state_topic: "test/water/day_begin"
name: water_day_begin
unit_of_measurement: l
สิ่งมหัศจรรย์ทั้งหมดเกิดขึ้นในระบบอัตโนมัติซึ่งทำงานทุกชั่วโมงและทุกคืนตามลำดับ
- id: water_new_hour
alias: water_new_hour
initial_state: true
trigger:
- platform: time_pattern
minutes: 0
action:
- service: mqtt.publish
data:
topic: "test/water/hour"
payload_template: >
{{ (states.sensor.water_meter_cold.state|int) - (states.sensor.water_hour_begin.state|int) }}
retain: true
- service: mqtt.publish
data:
topic: "test/water/hour_begin"
payload_template: >
{{ states.sensor.water_meter_cold.state }}
retain: true
- id: water_new_day
alias: water_new_day
initial_state: true
trigger:
- platform: time
at: "00:00:00"
action:
- service: mqtt.publish
data:
topic: "test/water/day"
payload_template: >
{{ (states.sensor.water_meter_cold.state|int) - (states.sensor.water_day_begin.state|int) }}
retain: true
- service: mqtt.publish
data:
topic: "test/water/day_begin"
payload_template: >
{{ states.sensor.water_meter_cold.state }}
retain: true
ระบบอัตโนมัติทั้งสองทำงาน 2 อย่าง:
- คำนวณค่าสำหรับช่วงเวลาเป็นผลต่างระหว่างค่าเริ่มต้นและสิ้นสุด
- อัพเดตค่าฐานสำหรับช่วงเวลาถัดไป
การสร้างกราฟในกรณีนี้ได้รับการแก้ไขโดยกราฟประวัติศาสตร์ตามปกติ:
- type: history-graph
title: 'Hourly water consumption using vars'
hours_to_show: 48
entities:
- sensor.water_hour
- type: history-graph
title: 'Daily water consumption using vars'
hours_to_show: 360
entities:
- sensor.water_day
ดูเหมือนว่านี้:
โดยหลักการแล้วนี่คือสิ่งที่จำเป็นอยู่แล้ว ข้อดีของวิธีนี้คือข้อมูลจะถูกสร้างขึ้นหนึ่งครั้งต่อช่วงเวลา เหล่านั้น. เพียง 24 บันทึกต่อวันสำหรับแผนภูมิรายชั่วโมง
น่าเสียดายที่สิ่งนี้ยังคงไม่สามารถแก้ปัญหาทั่วไปของฐานที่กำลังเติบโตได้ หากต้องการกราฟปริมาณการใช้รายเดือนจะต้องเก็บข้อมูลไว้อย่างน้อยหนึ่งปี และเนื่องจากผู้ช่วยที่บ้านมีการตั้งค่าระยะเวลาการจัดเก็บเพียงการตั้งค่าเดียวสำหรับทั้งฐานข้อมูล ซึ่งหมายความว่าข้อมูลทั้งหมดในระบบจะต้องถูกจัดเก็บตลอดทั้งปี ตัวอย่างเช่น ในหนึ่งปี ฉันใช้น้ำ 200 ลูกบาศก์เมตร ซึ่งหมายความว่านี่หมายถึง 200000 รายการในฐานข้อมูล และหากคุณคำนึงถึงเซ็นเซอร์อื่น ๆ โดยทั่วไปแล้วตัวเลขจะไม่เหมาะสม
แนวทางที่ 3
โชคดีที่คนฉลาดสามารถแก้ไขปัญหานี้ได้แล้วโดยการเขียนฐานข้อมูล InfluxDB ฐานข้อมูลนี้ได้รับการปรับปรุงเป็นพิเศษสำหรับการจัดเก็บข้อมูลตามเวลาและเหมาะอย่างยิ่งสำหรับการจัดเก็บค่าของเซ็นเซอร์ต่างๆ ระบบยังมีภาษาคิวรีที่คล้ายกับ SQL ที่ให้คุณดึงค่าจากฐานข้อมูลแล้วรวมเข้าด้วยกันในรูปแบบต่างๆ ในที่สุด ข้อมูลต่างๆ ก็สามารถจัดเก็บข้อมูลในช่วงเวลาที่ต่างกันได้ ตัวอย่างเช่น ค่าที่อ่านได้ซึ่งเปลี่ยนแปลงบ่อยครั้ง เช่น อุณหภูมิหรือความชื้นสามารถเก็บไว้ได้เพียงสองสามสัปดาห์ ในขณะที่ค่าที่อ่านได้ของการใช้น้ำในแต่ละวันสามารถเก็บไว้ได้ตลอดทั้งปี
นอกจาก InfluxDB แล้ว คนฉลาดยังคิดค้น Grafana ซึ่งเป็นระบบสำหรับวาดกราฟตามข้อมูลจาก InfluxDB Grafana สามารถวาดกราฟประเภทต่างๆ ปรับแต่งรายละเอียดได้ และที่สำคัญที่สุดคือกราฟเหล่านี้สามารถ “เสียบ” เข้ากับผู้ช่วยในบ้าน lovelace-UI ได้
ได้รับแรงบันดาลใจ
ก่อนอื่น เรามาเริ่มเพิ่มค่าตัวนับใน influxDB กันก่อน การกำหนดค่าผู้ช่วยที่บ้าน (ในตัวอย่างนี้ ฉันจะสนุกไม่เพียงแต่น้ำเย็นเท่านั้น แต่ยังรวมถึงน้ำร้อนด้วย):
influxdb:
host: localhost
max_retries: 3
default_measurement: state
database: homeassistant
include:
entities:
- sensor.water_meter_hot
- sensor.water_meter_cold
เรามาปิดการใช้งานการบันทึกข้อมูลเดียวกันนี้ลงในฐานข้อมูลผู้ช่วยภายในบ้านภายในเพื่อไม่ให้ขยายตัวอีกครั้ง:
recorder:
purge_keep_days: 10
purge_interval: 1
exclude:
entities:
- sensor.water_meter_hot
- sensor.water_meter_cold
ตอนนี้ไปที่คอนโซล InfluxDB และกำหนดค่าฐานข้อมูลของเรา โดยเฉพาะอย่างยิ่ง คุณต้องกำหนดค่าระยะเวลาที่จะจัดเก็บข้อมูลบางอย่าง สิ่งนี้ถูกควบคุมโดยสิ่งที่เรียกว่า นโยบายการเก็บรักษา - คล้ายกับฐานข้อมูลภายในฐานข้อมูลหลัก โดยแต่ละฐานข้อมูลภายในจะมีการตั้งค่าของตัวเอง ตามค่าเริ่มต้น ข้อมูลทั้งหมดจะถูกจัดเก็บไว้ในนโยบายการเก็บรักษาที่เรียกว่าออโตเจน ข้อมูลนี้จะถูกเก็บไว้เป็นเวลาหนึ่งสัปดาห์ ฉันต้องการให้เก็บข้อมูลรายชั่วโมงเป็นเวลาหนึ่งเดือน ข้อมูลรายสัปดาห์จะถูกเก็บไว้เป็นเวลาหนึ่งปี และข้อมูลรายเดือนจะไม่ถูกลบ มาสร้างนโยบายการเก็บรักษาที่เหมาะสมกันดีกว่า
CREATE RETENTION POLICY "month" ON "homeassistant" DURATION 30d REPLICATION 1
CREATE RETENTION POLICY "year" ON "homeassistant" DURATION 52w REPLICATION 1
CREATE RETENTION POLICY "infinite" ON "homeassistant" DURATION INF REPLICATION 1
ที่จริงแล้ว เคล็ดลับหลักคือการรวบรวมข้อมูลโดยใช้การสืบค้นอย่างต่อเนื่อง นี่คือกลไกที่เรียกใช้แบบสอบถามโดยอัตโนมัติตามช่วงเวลาที่ระบุ รวมข้อมูลสำหรับการสืบค้นนี้ และเพิ่มผลลัพธ์ลงในค่าใหม่ ลองดูตัวอย่าง (ฉันเขียนในคอลัมน์เพื่อให้อ่านง่าย แต่จริงๆ แล้วฉันต้องป้อนคำสั่งนี้ในหนึ่งบรรทัด)
CREATE CONTINUOUS QUERY cq_water_hourly ON homeassistant
BEGIN
SELECT max(value) AS value
INTO homeassistant.month.water_meter_hour
FROM homeassistant.autogen.l
GROUP BY time(1h), entity_id fill(previous)
END
คำสั่งนี้:
- สร้างเคียวรีต่อเนื่องชื่อ cq_water_cold_hourly ในฐานข้อมูล homeassistant
- คำขอจะดำเนินการทุกชั่วโมง (เวลา (1 ชม.))
- คำขอจะดึงข้อมูลทั้งหมดจากการวัด 'homeassistant.autogen.l (ลิตร) รวมถึงการอ่านค่าน้ำเย็นและน้ำร้อน
- ข้อมูลรวมจะถูกจัดกลุ่มตาม entert_id ซึ่งจะให้ค่าน้ำเย็นและน้ำร้อนแยกกัน
- เนื่องจากตัวนับลิตรเป็นลำดับที่เพิ่มขึ้นอย่างซ้ำซากจำเจภายในแต่ละชั่วโมง จึงจำเป็นต้องรับค่าสูงสุด ดังนั้นการรวมจะดำเนินการโดยฟังก์ชัน max(value)
- ค่าใหม่จะถูกเขียนไปที่ homeassistant.month.water_meter_hour โดยที่ month คือชื่อของนโยบายการเก็บรักษาซึ่งมีระยะเวลาการเก็บรักษาหนึ่งเดือน นอกจากนี้ ข้อมูลน้ำเย็นและน้ำร้อนจะกระจัดกระจายเป็นบันทึกแยกกันโดยมีentity_idและค่าที่สอดคล้องกันในช่องค่า
ในเวลากลางคืนหรือเมื่อไม่มีใครอยู่บ้าน จะไม่มีการใช้น้ำ ดังนั้นจึงไม่มีรายการใหม่ใน homeassistant.autogen.l เพื่อหลีกเลี่ยงค่าที่หายไปในการสืบค้นปกติ คุณสามารถใช้การเติม (ก่อนหน้า) สิ่งนี้จะบังคับให้ InfluxDB ใช้ค่าของชั่วโมงที่ผ่านมา
น่าเสียดายที่การสืบค้นอย่างต่อเนื่องมีลักษณะเฉพาะ: เคล็ดลับการเติม (ก่อนหน้า) ใช้ไม่ได้และเพียงแต่ไม่ได้สร้างเรกคอร์ด ยิ่งไปกว่านั้น นี่เป็นปัญหาบางอย่างที่ผ่านไม่ได้
มาดูกันว่าเกิดอะไรขึ้น (แน่นอนคุณต้องรอสองสามชั่วโมง):
> select * from homeassistant.month.water_meter_hour group by entity_id
...
name: water_meter_hour
tags: entity_id=water_meter_cold
time value
---- -----
...
2020-03-08T01:00:00Z 370511
2020-03-08T02:00:00Z 370513
2020-03-08T05:00:00Z 370527
2020-03-08T06:00:00Z 370605
2020-03-08T07:00:00Z 370635
2020-03-08T08:00:00Z 370699
2020-03-08T09:00:00Z 370761
2020-03-08T10:00:00Z 370767
2020-03-08T11:00:00Z 370810
2020-03-08T12:00:00Z 370818
2020-03-08T13:00:00Z 370827
2020-03-08T14:00:00Z 370849
2020-03-08T15:00:00Z 370921
โปรดทราบว่าค่าในฐานข้อมูลจะถูกจัดเก็บในรูปแบบ UTC ดังนั้นรายการนี้จึงแตกต่างกัน 3 ชั่วโมง - ค่า 7 น. ในเอาต์พุต InfluxDB สอดคล้องกับค่า 10 น. ในกราฟด้านบน โปรดทราบว่าระหว่างเวลา 2 ถึง 5 น. จะไม่มีบันทึกใด ๆ ซึ่งเป็นคุณลักษณะเดียวกันกับการสืบค้นแบบต่อเนื่อง
อย่างที่คุณเห็น ค่ารวมยังเป็นลำดับที่เพิ่มขึ้นแบบซ้ำซากจำเจ มีเพียงรายการเท่านั้นที่เกิดขึ้นไม่บ่อย - ครั้งต่อชั่วโมง แต่นี่ไม่ใช่ปัญหา เราสามารถเขียนแบบสอบถามอื่นที่จะดึงข้อมูลที่ถูกต้องสำหรับกราฟได้
SELECT difference(max(value))
FROM homeassistant.month.water_meter_hour
WHERE entity_id='water_meter_cold' and time >= now() -24h
GROUP BY time(1h), entity_id
fill(previous)
ฉันจะถอดรหัส:
- จากฐานข้อมูล homeassistant.month.water_meter_hour เราจะดึงข้อมูลสำหรับ entert_id='water_meter_cold' สำหรับวันสุดท้าย (เวลา >= ตอนนี้() -24 ชม.)
- ตามที่ฉันได้กล่าวไปแล้ว บางรายการอาจหายไปในลำดับ homeassistant.month.water_meter_hour เราจะสร้างข้อมูลนี้ใหม่โดยการเรียกใช้แบบสอบถามโดยแบ่งตามเวลา (1 ชม.) การเติมเวลานี้ (ก่อนหน้า) จะทำงานตามที่คาดไว้ โดยสร้างข้อมูลที่ขาดหายไป (ฟังก์ชันจะใช้ค่าก่อนหน้า)
- สิ่งที่สำคัญที่สุดในคำขอนี้คือฟังก์ชันผลต่าง ซึ่งจะคำนวณความแตกต่างระหว่างเครื่องหมายชั่วโมง มันไม่ทำงานด้วยตัวเองและต้องมีฟังก์ชันการรวมกลุ่ม ให้นี่คือค่าสูงสุด () ที่ใช้ก่อนหน้านี้
ผลการดำเนินการมีลักษณะเช่นนี้
name: water_meter_hour
tags: entity_id=water_meter_cold
time difference
---- ----------
...
2020-03-08T02:00:00Z 2
2020-03-08T03:00:00Z 0
2020-03-08T04:00:00Z 0
2020-03-08T05:00:00Z 14
2020-03-08T06:00:00Z 78
2020-03-08T07:00:00Z 30
2020-03-08T08:00:00Z 64
2020-03-08T09:00:00Z 62
2020-03-08T10:00:00Z 6
2020-03-08T11:00:00Z 43
2020-03-08T12:00:00Z 8
2020-03-08T13:00:00Z 9
2020-03-08T14:00:00Z 22
2020-03-08T15:00:00Z 72
ตั้งแต่ตี 2 ถึงตี 5 (UTC) ไม่มีการบริโภค อย่างไรก็ตาม คิวรีจะส่งคืนค่าปริมาณการใช้เท่าเดิมด้วยการเติม (ก่อนหน้า) และฟังก์ชันผลต่างจะลบค่านี้ออกจากตัวมันเอง และเอาต์พุตจะเป็น 0 ซึ่งเป็นค่าที่จำเป็นอย่างแน่นอน
สิ่งที่เหลืออยู่คือการสร้างกราฟ ในการดำเนินการนี้ ให้เปิด Grafana เปิดแดชบอร์ดที่มีอยู่ (หรือสร้างใหม่) และสร้างแผงใหม่ การตั้งค่ากราฟจะเป็นแบบนี้
ฉันจะแสดงข้อมูลน้ำเย็นและน้ำร้อนบนกราฟเดียวกัน คำขอเหมือนกับที่ฉันอธิบายไว้ข้างต้นทุกประการ
พารามิเตอร์การแสดงผลได้รับการตั้งค่าดังนี้ สำหรับฉันมันจะเป็นกราฟที่มีเส้นเป็นขั้นบันได (บันได) ฉันจะอธิบายพารามิเตอร์ Stack ด้านล่าง มีตัวเลือกการแสดงผลเพิ่มเติมสองสามตัวเลือกด้านล่าง แต่ก็ไม่ได้น่าสนใจขนาดนั้น
หากต้องการเพิ่มแผนภูมิผลลัพธ์ให้กับผู้ช่วยที่บ้าน คุณต้อง:
- ออกจากโหมดแก้ไขแผนภูมิ ด้วยเหตุผลบางประการ การตั้งค่าการแชร์แผนภูมิที่ถูกต้องจะมีให้จากหน้าแดชบอร์ดเท่านั้น
- คลิกที่สามเหลี่ยมถัดจากชื่อแผนภูมิและเลือกแชร์จากเมนู
- ในหน้าต่างที่เปิดขึ้น ให้ไปที่แท็บฝัง
- ยกเลิกการเลือกช่วงเวลาปัจจุบัน - เราจะกำหนดช่วงเวลาผ่าน URL
- เลือกหัวข้อที่ต้องการ ในกรณีของฉันมันเบา
- คัดลอก URL ผลลัพธ์ไปยังการ์ดการตั้งค่า lovelace-UI
- type: iframe
id: graf_water_hourly
url: "http://192.168.10.200:3000/d-solo/rZARemQWk/water?orgId=1&panelId=2&from=now-2d&to=now&theme=light"
โปรดทราบว่าช่วงเวลา (2 วันที่ผ่านมา) ถูกกำหนดไว้ที่นี่ ไม่ใช่ในการตั้งค่าแดชบอร์ด
กราฟมีลักษณะเช่นนี้ ฉันไม่ได้ใช้น้ำร้อนในช่วง 2 วันที่ผ่านมา ดังนั้นจึงวาดเฉพาะกราฟน้ำเย็นเท่านั้น
ฉันยังไม่ได้ตัดสินใจด้วยตัวเองว่ากราฟไหนที่ฉันชอบมากกว่า เส้นขั้น หรือแท่งจริง ดังนั้น ฉันจะยกตัวอย่างแผนภูมิการบริโภครายวันเฉพาะครั้งนี้ในแท่งเท่านั้น แบบสอบถามถูกสร้างขึ้นคล้ายกับที่อธิบายไว้ข้างต้น ตัวเลือกการแสดงผลคือ:
กราฟนี้มีลักษณะดังนี้:
ดังนั้นเกี่ยวกับพารามิเตอร์ Stack ในกราฟนี้ คอลัมน์น้ำเย็นจะถูกวาดทับคอลัมน์น้ำร้อน ความสูงรวมสอดคล้องกับปริมาณการใช้น้ำเย็นและน้ำร้อนทั้งหมดในช่วงเวลานั้น
กราฟทั้งหมดที่แสดงเป็นไดนามิก คุณสามารถเลื่อนเมาส์ไว้เหนือจุดสนใจและดูรายละเอียดและมูลค่า ณ จุดใดจุดหนึ่งได้
น่าเสียดายที่มีแมลงวันสองสามตัวอยู่ในครีม บนแผนภูมิแท่ง (ไม่เหมือนกับแผนภูมิที่มีเส้นขั้น) จุดกึ่งกลางของแท่งไม่ได้อยู่ตรงกลางของวัน แต่อยู่ที่เวลา 00:00 น. เหล่านั้น. ครึ่งซ้ายของคอลัมน์จะถูกวาดแทนที่วันก่อนหน้า ดังนั้นกราฟสำหรับวันเสาร์และวันอาทิตย์จึงถูกลากไปทางด้านซ้ายของโซนสีน้ำเงินเล็กน้อย จนกระทั่งฉันรู้วิธีเอาชนะมัน
ปัญหาอีกประการหนึ่งคือการไม่สามารถทำงานได้อย่างถูกต้องตามช่วงเวลาทุกเดือน ความจริงก็คือความยาวของชั่วโมง/วัน/สัปดาห์ได้รับการแก้ไขแล้ว แต่ความยาวของเดือนจะแตกต่างกันในแต่ละครั้ง InfluxDB สามารถทำงานได้ในช่วงเวลาที่เท่ากันเท่านั้น จนถึงตอนนี้สมองของฉันเพียงพอที่จะกำหนดช่วงเวลาคงที่ไว้ที่ 30 วัน ใช่ กราฟจะลอยตัวเล็กน้อยตลอดทั้งปี และแท่งกราฟจะไม่ตรงกับเดือนทุกประการ แต่เนื่องจากฉันสนใจสิ่งนี้เพียงเพื่อใช้เป็นมิเตอร์แสดงผล ฉันก็โอเคกับมัน
ฉันเห็นวิธีแก้ปัญหาอย่างน้อยสองวิธี:
- ยอมแพ้กับกราฟรายเดือนและจำกัดตัวเองให้อยู่แค่กราฟรายสัปดาห์ 52 บาร์รายสัปดาห์สำหรับปีดูค่อนข้างดี
- พิจารณาการบริโภครายเดือนเป็นวิธีที่ 2 และใช้กราฟาน่าสำหรับกราฟที่สวยงามเท่านั้น มันจะเป็นทางออกที่ค่อนข้างแม่นยำ คุณยังสามารถซ้อนทับกราฟของปีที่ผ่านมาเพื่อเปรียบเทียบได้ - grafana ก็สามารถทำได้เช่นกัน
ข้อสรุป
ฉันไม่รู้ว่าทำไม แต่ฉันหมกมุ่นอยู่กับกราฟประเภทนี้ พวกเขาแสดงให้เห็นว่าชีวิตเต็มไปด้วยความผันผวนและทุกสิ่งกำลังเปลี่ยนแปลง เมื่อวานมีมาก วันนี้มีน้อย พรุ่งนี้จะเป็นอย่างอื่น สิ่งที่เหลืออยู่คือการทำงานร่วมกับสมาชิกในครัวเรือนในหัวข้อการบริโภค แต่ถึงแม้จะมีความอยากอาหารในปัจจุบัน แต่ตัวเลขในใบชำระเงินที่มีขนาดใหญ่และไม่สามารถเข้าใจได้ก็กลายเป็นภาพการบริโภคที่ค่อนข้างเข้าใจได้
แม้ว่าฉันจะทำงานเป็นโปรแกรมเมอร์มาเกือบ 20 ปี แต่ฉันแทบจะไม่เคยติดต่อกับฐานข้อมูลเลย ดังนั้นการติดตั้งฐานข้อมูลภายนอกจึงดูซับซ้อนและเข้าใจยากมาก เปลี่ยนแปลงทุกอย่าง
ในชื่อเรื่องฉันกล่าวถึงปริมาณการใช้ไฟฟ้า ขออภัย ขณะนี้ฉันไม่สามารถแสดงกราฟใดๆ ได้ SDM120 เมตรหนึ่งตายสำหรับฉัน และอีกอันหนึ่งมีข้อผิดพลาดเมื่อเข้าถึงผ่าน Modbus อย่างไรก็ตาม สิ่งนี้จะไม่ส่งผลกระทบต่อหัวข้อของบทความนี้แต่อย่างใด - กราฟจะถูกสร้างขึ้นในลักษณะเดียวกับน้ำ
ในบทความนี้ ฉันนำเสนอแนวทางที่ฉันลองด้วยตัวเอง แน่นอนว่ามีวิธีอื่นในการจัดระเบียบการรวบรวมข้อมูลและการแสดงภาพที่ฉันไม่รู้ บอกฉันเกี่ยวกับเรื่องนี้ในความคิดเห็นฉันจะสนใจมาก ฉันยินดีที่จะวิจารณ์อย่างสร้างสรรค์และแนวคิดใหม่ ๆ ฉันหวังว่าเนื้อหาที่นำเสนอจะช่วยใครบางคนได้เช่นกัน
ที่มา: will.com