บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant

บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant
ทุกครั้งที่ได้รับค่าไฟฟ้าและค่าน้ำ ก็ต้องแปลกใจ ครอบครัวของฉันใช้ไฟฟ้าเยอะขนาดนี้เลยหรือ? ใช่ ห้องน้ำมีพื้นระบบทำความร้อนและหม้อต้มน้ำ แต่ไม่ได้จุดไฟตลอดเวลา ดูเหมือนเราจะประหยัดน้ำด้วย (แม้ว่าเราจะชอบเล่นน้ำในห้องน้ำก็ตาม) เมื่อหลายปีก่อนฉันแล้ว มิเตอร์น้ำที่เชื่อมต่อ и ไฟฟ้า สู่บ้านอัจฉริยะ แต่นั่นคือสิ่งที่เกิดปัญหา ตอนนี้เราเพิ่งจะวิเคราะห์การบริโภคได้ ซึ่งเป็นสิ่งที่บทความนี้พูดถึงจริงๆ

ฉันเพิ่งเปลี่ยนมาใช้ 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 คือค่ามิเตอร์ปัจจุบันในหน่วยลิตรที่ฉันได้รับ โดยตรงจากเศษเหล็ก โดย mqtt. การออกแบบนี้สร้างเซ็นเซอร์ใหม่ 2 ตัว water_cold_hour_um และ water_cold_day_um ซึ่งจะสะสมการอ่านค่ารายชั่วโมงและรายวัน โดยรีเซ็ตเป็นศูนย์หลังจากพ้นระยะเวลาดังกล่าว นี่คือกราฟแบตเตอรี่รายชั่วโมงเป็นเวลาครึ่งวัน

บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant

รหัสสำหรับแผนภูมิรายชั่วโมงและรายวันสำหรับ 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 - รับค่าสูงสุดภายในแต่ละชั่วโมง พารามิเตอร์นี้เองที่เปลี่ยนกราฟฟันเลื่อยให้เป็นแท่ง

บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant

อย่าไปสนใจแถวของคอลัมน์ทางด้านซ้าย นี่เป็นลักษณะการทำงานมาตรฐานของส่วนประกอบหากไม่มีข้อมูล แต่ไม่มีข้อมูล - ฉันเปิดการรวบรวมข้อมูลมิเตอร์สาธารณูปโภคเมื่อสองสามชั่วโมงที่แล้วเพื่อประโยชน์ของบทความนี้เท่านั้น (ฉันจะอธิบายแนวทางปัจจุบันของฉันด้านล่าง)

ในภาพนี้ ฉันต้องการแสดงให้เห็นว่าบางครั้งการแสดงข้อมูลยังใช้งานได้ และแถบก็สะท้อนค่าที่ถูกต้องจริงๆ แต่นั่นไม่ใช่ทั้งหมด ด้วยเหตุผลบางประการ คอลัมน์ที่เลือกในช่วงเวลาตั้งแต่ 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

ดูเหมือนว่านี้:

บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant

โดยหลักการแล้วนี่คือสิ่งที่จำเป็นอยู่แล้ว ข้อดีของวิธีนี้คือข้อมูลจะถูกสร้างขึ้นหนึ่งครั้งต่อช่วงเวลา เหล่านั้น. เพียง 24 บันทึกต่อวันสำหรับแผนภูมิรายชั่วโมง

น่าเสียดายที่สิ่งนี้ยังคงไม่สามารถแก้ปัญหาทั่วไปของฐานที่กำลังเติบโตได้ หากต้องการกราฟปริมาณการใช้รายเดือนจะต้องเก็บข้อมูลไว้อย่างน้อยหนึ่งปี และเนื่องจากผู้ช่วยที่บ้านมีการตั้งค่าระยะเวลาการจัดเก็บเพียงการตั้งค่าเดียวสำหรับทั้งฐานข้อมูล ซึ่งหมายความว่าข้อมูลทั้งหมดในระบบจะต้องถูกจัดเก็บตลอดทั้งปี ตัวอย่างเช่น ในหนึ่งปี ฉันใช้น้ำ 200 ลูกบาศก์เมตร ซึ่งหมายความว่านี่หมายถึง 200000 รายการในฐานข้อมูล และหากคุณคำนึงถึงเซ็นเซอร์อื่น ๆ โดยทั่วไปแล้วตัวเลขจะไม่เหมาะสม

แนวทางที่ 3

โชคดีที่คนฉลาดสามารถแก้ไขปัญหานี้ได้แล้วโดยการเขียนฐานข้อมูล InfluxDB ฐานข้อมูลนี้ได้รับการปรับปรุงเป็นพิเศษสำหรับการจัดเก็บข้อมูลตามเวลาและเหมาะอย่างยิ่งสำหรับการจัดเก็บค่าของเซ็นเซอร์ต่างๆ ระบบยังมีภาษาคิวรีที่คล้ายกับ SQL ที่ให้คุณดึงค่าจากฐานข้อมูลแล้วรวมเข้าด้วยกันในรูปแบบต่างๆ ในที่สุด ข้อมูลต่างๆ ก็สามารถจัดเก็บข้อมูลในช่วงเวลาที่ต่างกันได้ ตัวอย่างเช่น ค่าที่อ่านได้ซึ่งเปลี่ยนแปลงบ่อยครั้ง เช่น อุณหภูมิหรือความชื้นสามารถเก็บไว้ได้เพียงสองสามสัปดาห์ ในขณะที่ค่าที่อ่านได้ของการใช้น้ำในแต่ละวันสามารถเก็บไว้ได้ตลอดทั้งปี

นอกจาก InfluxDB แล้ว คนฉลาดยังคิดค้น Grafana ซึ่งเป็นระบบสำหรับวาดกราฟตามข้อมูลจาก InfluxDB Grafana สามารถวาดกราฟประเภทต่างๆ ปรับแต่งรายละเอียดได้ และที่สำคัญที่สุดคือกราฟเหล่านี้สามารถ “เสียบ” เข้ากับผู้ช่วยในบ้าน lovelace-UI ได้

ได้รับแรงบันดาลใจ ที่นี่ и ที่นี่. บทความอธิบายรายละเอียดกระบวนการติดตั้งและเชื่อมต่อ InfluxDB และ Grafana กับผู้ช่วยที่บ้าน ฉันจะมุ่งเน้นไปที่การแก้ปัญหาเฉพาะของฉัน

ก่อนอื่น เรามาเริ่มเพิ่มค่าตัวนับใน 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 เปิดแดชบอร์ดที่มีอยู่ (หรือสร้างใหม่) และสร้างแผงใหม่ การตั้งค่ากราฟจะเป็นแบบนี้

บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant

ฉันจะแสดงข้อมูลน้ำเย็นและน้ำร้อนบนกราฟเดียวกัน คำขอเหมือนกับที่ฉันอธิบายไว้ข้างต้นทุกประการ

พารามิเตอร์การแสดงผลได้รับการตั้งค่าดังนี้ สำหรับฉันมันจะเป็นกราฟที่มีเส้นเป็นขั้นบันได (บันได) ฉันจะอธิบายพารามิเตอร์ Stack ด้านล่าง มีตัวเลือกการแสดงผลเพิ่มเติมสองสามตัวเลือกด้านล่าง แต่ก็ไม่ได้น่าสนใจขนาดนั้น

บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant

หากต้องการเพิ่มแผนภูมิผลลัพธ์ให้กับผู้ช่วยที่บ้าน คุณต้อง:

  • ออกจากโหมดแก้ไขแผนภูมิ ด้วยเหตุผลบางประการ การตั้งค่าการแชร์แผนภูมิที่ถูกต้องจะมีให้จากหน้าแดชบอร์ดเท่านั้น
  • คลิกที่สามเหลี่ยมถัดจากชื่อแผนภูมิและเลือกแชร์จากเมนู
  • ในหน้าต่างที่เปิดขึ้น ให้ไปที่แท็บฝัง
  • ยกเลิกการเลือกช่วงเวลาปัจจุบัน - เราจะกำหนดช่วงเวลาผ่าน 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 วันที่ผ่านมา ดังนั้นจึงวาดเฉพาะกราฟน้ำเย็นเท่านั้น

บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant

ฉันยังไม่ได้ตัดสินใจด้วยตัวเองว่ากราฟไหนที่ฉันชอบมากกว่า เส้นขั้น หรือแท่งจริง ดังนั้น ฉันจะยกตัวอย่างแผนภูมิการบริโภครายวันเฉพาะครั้งนี้ในแท่งเท่านั้น แบบสอบถามถูกสร้างขึ้นคล้ายกับที่อธิบายไว้ข้างต้น ตัวเลือกการแสดงผลคือ:

บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant

กราฟนี้มีลักษณะดังนี้:

บ้านอัจฉริยะ: เราสร้างกราฟปริมาณการใช้น้ำและไฟฟ้าใน Home Assistant

ดังนั้นเกี่ยวกับพารามิเตอร์ Stack ในกราฟนี้ คอลัมน์น้ำเย็นจะถูกวาดทับคอลัมน์น้ำร้อน ความสูงรวมสอดคล้องกับปริมาณการใช้น้ำเย็นและน้ำร้อนทั้งหมดในช่วงเวลานั้น

กราฟทั้งหมดที่แสดงเป็นไดนามิก คุณสามารถเลื่อนเมาส์ไว้เหนือจุดสนใจและดูรายละเอียดและมูลค่า ณ จุดใดจุดหนึ่งได้

น่าเสียดายที่มีแมลงวันสองสามตัวอยู่ในครีม บนแผนภูมิแท่ง (ไม่เหมือนกับแผนภูมิที่มีเส้นขั้น) จุดกึ่งกลางของแท่งไม่ได้อยู่ตรงกลางของวัน แต่อยู่ที่เวลา 00:00 น. เหล่านั้น. ครึ่งซ้ายของคอลัมน์จะถูกวาดแทนที่วันก่อนหน้า ดังนั้นกราฟสำหรับวันเสาร์และวันอาทิตย์จึงถูกลากไปทางด้านซ้ายของโซนสีน้ำเงินเล็กน้อย จนกระทั่งฉันรู้วิธีเอาชนะมัน

ปัญหาอีกประการหนึ่งคือการไม่สามารถทำงานได้อย่างถูกต้องตามช่วงเวลาทุกเดือน ความจริงก็คือความยาวของชั่วโมง/วัน/สัปดาห์ได้รับการแก้ไขแล้ว แต่ความยาวของเดือนจะแตกต่างกันในแต่ละครั้ง InfluxDB สามารถทำงานได้ในช่วงเวลาที่เท่ากันเท่านั้น จนถึงตอนนี้สมองของฉันเพียงพอที่จะกำหนดช่วงเวลาคงที่ไว้ที่ 30 วัน ใช่ กราฟจะลอยตัวเล็กน้อยตลอดทั้งปี และแท่งกราฟจะไม่ตรงกับเดือนทุกประการ แต่เนื่องจากฉันสนใจสิ่งนี้เพียงเพื่อใช้เป็นมิเตอร์แสดงผล ฉันก็โอเคกับมัน

ฉันเห็นวิธีแก้ปัญหาอย่างน้อยสองวิธี:

  • ยอมแพ้กับกราฟรายเดือนและจำกัดตัวเองให้อยู่แค่กราฟรายสัปดาห์ 52 บาร์รายสัปดาห์สำหรับปีดูค่อนข้างดี
  • พิจารณาการบริโภครายเดือนเป็นวิธีที่ 2 และใช้กราฟาน่าสำหรับกราฟที่สวยงามเท่านั้น มันจะเป็นทางออกที่ค่อนข้างแม่นยำ คุณยังสามารถซ้อนทับกราฟของปีที่ผ่านมาเพื่อเปรียบเทียบได้ - grafana ก็สามารถทำได้เช่นกัน

ข้อสรุป

ฉันไม่รู้ว่าทำไม แต่ฉันหมกมุ่นอยู่กับกราฟประเภทนี้ พวกเขาแสดงให้เห็นว่าชีวิตเต็มไปด้วยความผันผวนและทุกสิ่งกำลังเปลี่ยนแปลง เมื่อวานมีมาก วันนี้มีน้อย พรุ่งนี้จะเป็นอย่างอื่น สิ่งที่เหลืออยู่คือการทำงานร่วมกับสมาชิกในครัวเรือนในหัวข้อการบริโภค แต่ถึงแม้จะมีความอยากอาหารในปัจจุบัน แต่ตัวเลขในใบชำระเงินที่มีขนาดใหญ่และไม่สามารถเข้าใจได้ก็กลายเป็นภาพการบริโภคที่ค่อนข้างเข้าใจได้

แม้ว่าฉันจะทำงานเป็นโปรแกรมเมอร์มาเกือบ 20 ปี แต่ฉันแทบจะไม่เคยติดต่อกับฐานข้อมูลเลย ดังนั้นการติดตั้งฐานข้อมูลภายนอกจึงดูซับซ้อนและเข้าใจยากมาก เปลี่ยนแปลงทุกอย่าง บทความข้างต้น — ปรากฎว่าการแนบเครื่องมือที่เหมาะสมทำได้ด้วยการคลิกเพียงไม่กี่ครั้ง และด้วยเครื่องมือพิเศษ งานการลงจุดแผนภูมิจึงง่ายขึ้นเล็กน้อย

ในชื่อเรื่องฉันกล่าวถึงปริมาณการใช้ไฟฟ้า ขออภัย ขณะนี้ฉันไม่สามารถแสดงกราฟใดๆ ได้ SDM120 เมตรหนึ่งตายสำหรับฉัน และอีกอันหนึ่งมีข้อผิดพลาดเมื่อเข้าถึงผ่าน Modbus อย่างไรก็ตาม สิ่งนี้จะไม่ส่งผลกระทบต่อหัวข้อของบทความนี้แต่อย่างใด - กราฟจะถูกสร้างขึ้นในลักษณะเดียวกับน้ำ

ในบทความนี้ ฉันนำเสนอแนวทางที่ฉันลองด้วยตัวเอง แน่นอนว่ามีวิธีอื่นในการจัดระเบียบการรวบรวมข้อมูลและการแสดงภาพที่ฉันไม่รู้ บอกฉันเกี่ยวกับเรื่องนี้ในความคิดเห็นฉันจะสนใจมาก ฉันยินดีที่จะวิจารณ์อย่างสร้างสรรค์และแนวคิดใหม่ ๆ ฉันหวังว่าเนื้อหาที่นำเสนอจะช่วยใครบางคนได้เช่นกัน

ที่มา: will.com

เพิ่มความคิดเห็น