Skip to content
עברית

תוכנה לרשת החשמל: ארכיטקטורת אנרגיה מבוזרת וניהול סוללות

פריסת סוללות מעלה שאלות מועילות בהנדסת תוכנה. מדוע שמאמר על תוכנה ו־DevOps יעסוק במערכות סוללות ליתיום־יון? משום שהניטור, עיבוד הנתונים והתיאום שלהן מערבים תוכנה, אף שתכנון הבטיחות נשען גם על חומרה ועל הנדסה המותאמת לסוג התא. [מקור 1] [מקור 2]

מערכות סוללות משלבות חומרה עם בקרה משובצת, ובחלק מהפריסות גם תוכנת שער וענן. יכולת הספק נמדדת במגה־ואט; קיבולת אנרגיה אגורה נמדדת במגה־ואט־שעה. הגנת הסוללה המקומית אינה אמורה להסתמך על קוד הדגמה זה לטלמטריה בענן. [מקור 1] [מקור 2]

בין שמדובר ב־Tesla Powerwall ביתי, בגיבוי סוללות מסחרי או באגירה לרשת בקנה מידה של חברת חשמל, מפתחי תוכנה הם שכותבים את לולאות הבקרה, את שילובי ה־API ואת צינורות הנתונים שמאפשרים אגירת אנרגיה מודרנית. היום נצלול לארכיטקטורה של מערכות ניהול סוללות (BMS), נבחן עיבוד טלמטריה בתפוקה גבוהה ונכתוב קוד ב־Go להדמיית שירות לניטור תאי סוללה בזמן אמת.

הארכיטקטורה של תוכנת סוללות מודרנית

כדי להבין היכן אנחנו משתלבים כמפתחים, צריך לבחון את השכבות של תוכנת הסוללות. לא מדובר רק בתמונת קושחה אחת שנצרבת בשבב, אלא במערכת מבוזרת בעלת כמה שכבות.

  • שכבת הקצה — קושחת BMS: בקרי סוללות יכולים להשתמש בשפות כגון C, C++ או Rust. ב־BMS האלקטרוניקה המקומית מנטרת את מתח התאים, זרם המארז והטמפרטורה, ואוכפת מנגנוני הגנה שנבדקו. המימוש והספים תלויים בחומרה שנבחרה ובכימיית התאים. [מקור 1]
  • שכבת השער או איסוף הנתונים: פועלת לעיתים קרובות במחשבים תעשייתיים או בשערי קצה, באמצעות Linux או מערכת הפעלה בזמן אמת (RTOS). השכבה הזו מאגדת נתונים מאלפי תאים, מבצעת סינון מקומי ומתקשרת בפרוטוקולים כגון Modbus TCP, אפיק CAN או gRPC.
  • שכבת הענן וקליטת הנתונים: פלטפורמה לניהול צי עשויה לאגד טלמטריה, להעריך את בריאות הסוללה ולתמוך בתזמון או בהשתתפות בשווקים. הקצבים והיכולות תלויים בפריסה; חיבור לענן או מודל למידת מכונה אינם תחליף להגנת סוללה מקומית עצמאית. [מקור 1]

אתגר הטלמטריה

באתר היפותטי ובו 10,000 מארזים, 24 תאים למארז ו־10 דגימות בשנייה, הקצב הוא 2.4 מיליון רשומות של דגימות תאים בשנייה. אם בכל רשומה שלושה מדדים סקלריים, מתקבלים 7.2 מיליון ערכים סקלריים בשנייה. אלה הנחות לחישוב, לא קצבי טלמטריה שנמדדו; בתכנון ממשי יש להגדיר אילו גדלים נמדדים ברמת התא, מחרוזת התאים והמארז. [מקור 1]

בניית מעבד טלמטריית סוללות בזמן אמת ב־Go

השירות ייצור מדדי תאים סינתטיים בזיכרון ויעביר אותם בערוצי Go. הוא אינו מממש קבלה דרך gRPC או WebSocket, אימות קלט או כתיבה למסד נתונים. ספי ההדגמה השרירותיים שלו אינם ספי בטיחות מאומתים. [מקור 1] [מקור 2] [מקור 3]

Go מספקת goroutines וערוצים שבעזרתם אפשר להדגים קליטה מקבילית. הנה תכנון אפשרי של מאגר עובדים; התאמה וביצועים דורשים בדיקה בעומס העבודה המסוים. [מקור 1]

package main

import (
	"context"
	"fmt"
	"math/rand"
	"sync"
	"time"
)

// BatteryMetrics represents the telemetry payload from a battery pack
type BatteryMetrics struct {
	PackID    string    `json:"pack_id"`
	CellID    int       `json:"cell_id"`
	Voltage   float64   `json:"voltage"`     // in Volts
	Current   float64   `json:"current"`     // in Amperes
	TempC     float64   `json:"temperature"` // in Celsius
	Timestamp time.Time `json:"timestamp"`
}

// SafetyAlert represents a synthetic threshold event in this teaching simulation
type SafetyAlert struct {
	PackID  string
	Message string
	Level   string // WARNING, CRITICAL, EMERGENCY
}

// Worker processes incoming telemetry packets
func Worker(id int, metricsChan <-chan BatteryMetrics, alertChan chan<- SafetyAlert, wg *sync.WaitGroup) {
	defer wg.Done()
	fmt.Printf("[Worker %d] Started telemetry processor\n", id)

	for metric := range metricsChan {
		// Synthetic demonstration threshold only; not a thermal-runaway detector.
		// Do not use this value to protect real cells or control equipment.
		if metric.TempC > 58.0 {
			alertChan <- SafetyAlert{
				PackID:  metric.PackID,
				Message: fmt.Sprintf("CRITICAL TEMP DETECTED: Cell %d is at %.2f°C", metric.CellID, metric.TempC),
				Level:   "EMERGENCY",
			}
		}

		// Synthetic voltage threshold only; cell chemistry and manufacturer limits differ.
		if metric.Voltage > 4.25 {
			alertChan <- SafetyAlert{
				PackID:  metric.PackID,
				Message: fmt.Sprintf("Overvoltage on Cell %d: %.2fV", metric.CellID, metric.Voltage),
				Level:   "CRITICAL",
			}
		}

		// Simulate writing to a time-series database (e.g., InfluxDB, TimescaleDB)
		// in a real app, you'd batch these writes to disk/network
		_ = metric
	}
}

כעת נפעיל את העובדים, ניצור נתונים סינתטיים ונדפיס התראות מדומות באופן אסינכרוני. הגרסה הזו ממתינה לסיום מאזין ההתראות לאחר עצירת העובדים. זו דוגמת לימוד בזיכרון בלבד: אין בה שילוב עם חומרה, מקלט רשת, רכיב הפעלה או מסד נתונים, והיא אינה מערכת בטיחות או שליחת התראות לייצור. [מקור 1] [מקור 2]

func main() {
	// Go 1.24+: package-level math/rand is automatically seeded; Seed is a no-op by default.

	metricsChan := make(chan BatteryMetrics, 1000)
	alertChan := make(chan SafetyAlert, 100)
	var wg sync.WaitGroup

	// Start a pool of 4 workers to handle high-throughput edge telemetry
	numWorkers := 4
	for i := 1; i <= numWorkers; i++ {
		wg.Add(1)
		go Worker(i, metricsChan, alertChan, &wg)
	}

	// Print synthetic alerts only; never connect this demo to safety systems or actuators.
	alertDone := make(chan struct{})
	go func() {
		defer close(alertDone)
		for alert := range alertChan {
			fmt.Printf("\n🚨 [SIMULATED ALERT - %s] Pack: %s - %s\n\n", alert.Level, alert.PackID, alert.Message)
		}
	}()

	// Generate a small synthetic telemetry stream in memory
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	go func() {
		for {
			select {
			case <-ctx.Done():
				close(metricsChan)
				return
			default:
				// Simulate normal operation with occasional spikes
				temp := 25.0 + rand.Float64()*15.0
				if rand.Float64() > 0.98 {
					temp = 62.5 // Arbitrary synthetic spike; not a validated thermal-event model
				}

				metricsChan <- BatteryMetrics{
					PackID:    "pack-us-east-09a",
					CellID:    rand.Intn(16),
					Voltage:   3.2 + rand.Float64()*1.1,
					Current:   12.5,
					TempC:     temp,
					Timestamp: time.Now(),
				}
				time.Sleep(10 * time.Millisecond) // 100 Hz simulation stream
			}
		}
	}()

	wg.Wait()
	close(alertChan)
	<-alertDone
	fmt.Println("Simulation finished; all queued alerts were printed.")
}

פתרון בעיית האחסון: מסדי נתוני סדרות זמן בקנה מידה גדול

טלמטריית סוללות היא עומס עבודה של סדרות זמן. יש לבחון PostgreSQL, MySQL ומסדי נתונים ייעודיים לפי קצב הקליטה, דפוסי השאילתות, תקופת השמירה והחומרה בפועל; מספר הבתים לבדו אינו קובע אם מסד הנתונים יעמוד בעומס. [מקור 1]

בין האפשרויות שכדאי לבחון:

  • TimescaleDB: הרחבה ל־PostgreSQL שמספקת hypertables המחולקות לפי זמן ושאילתות SQL, כולל צירופים למטא־נתונים של לקוחות או אתרים. התאמתה תלויה בעומס העבודה. [מקור 1]
  • InfluxDB או Prometheus: אפשרויות נוספות לאחסון מדדים, שיש לבחון מול דרישות הקליטה, השמירה והשאילתות. [מקור 1] [מקור 2]
  • Apache Cassandra או ScyllaDB: אפשרויות נוספות לאחסון מבוזר שכדאי לבחון. המאמר אינו מציג ראיות לאימוצן בידי מאגדי אנרגיה. [מקור 1] [מקור 2]

תכנון סכמת מסד הנתונים

אם אתם משתמשים בגרסת TimescaleDB שתומכת בממשק הדחיסה הוותיק שלהלן, זו סכמה לדוגמה. יש להפעיל את ההרחבה בנפרד ולבדוק את הדוגמה מול גרסה שנקבעה מראש. ממשק הדחיסה מוגדר ותיק מאז 2.18.0 אך עדיין נתמך; דחיסה נבדלת ממדיניות שמירה או מארכוב חיצוני. [מקור 1] [מקור 2]

-- Create a standard PostgreSQL table
CREATE TABLE battery_telemetry (
    time TIMESTAMPTZ NOT NULL,
    pack_id TEXT NOT NULL,
    cell_id INT NOT NULL,
    voltage DOUBLE PRECISION,
    current DOUBLE PRECISION,
    temperature DOUBLE PRECISION
);

-- Convert it into a TimescaleDB hypertable partitioned by time
SELECT create_hypertable('battery_telemetry', 'time');

-- Enable legacy compression before scheduling it.
-- This compresses older chunks; it does not delete or externally archive data.
ALTER TABLE battery_telemetry SET (
    timescaledb.compress,
    timescaledb.compress_segmentby = 'pack_id'
);
SELECT add_compression_policy('battery_telemetry', INTERVAL '30 days');

רשת חשמל מבוססת ענן: תחנות כוח וירטואליות (VPPs)

חלק מהסוללות משתתפות בשירותים לרשת החשמל. תחנות כוח וירטואליות הן דרך אחת לתאם משאבי אנרגיה מבוזרים. [מקור 1]

תחנת כוח וירטואלית מתאמת משאבים מבוזרים כגון אגירה, ייצור וביקוש גמיש כדי לספק שירותים לרשת. תרומתה לאמינות תלויה בזמינות המשאבים, בתקשורת ובמגבלות התפעול; פריקה מתואמת אינה מבטיחה מניעת הפסקות חשמל. [מקור 1]

מערך הטכנולוגיות של VPP

כיעד הנדסי היפותטי, נבחן תיאום של 50,000 סוללות ביתיות בתוך שתי שניות. המאמר אינו מדגים השהיה כזו או שירות תגובה לשינויי תדר. [מקור 1]

  1. העברת הודעות מונחית אירועים: תכנון עשוי להשתמש במתווך הודעות בענן ובשערים שמתקשרים עם ההתקנים. צריך לתכנן במפורש השהיה מקצה לקצה, אישורים, אימות זהות וטיפול בתקלות; עצם הבחירה ב־Kafka או במתווך MQTT אינה מבססת את ההבטחות האלה.
  2. תיאום באמצעות שחקנים: Akka/Pekko יכולות לייצג התקנים כשחקנים ולנתב פקודות. מודל השחקנים לבדו אינו מבטיח הסכמה מבוזרת; יש להגדיר בנפרד עקביות והתנהגות בעת פיצול רשת. [מקור 1]
  3. מידול לחיזוי: מודלים עשויים לסייע בתזמון על סמך מזג האוויר, ביקוש היסטורי ומחירים. התועלת שלהם תלויה באיכות הנתונים, בהערכה ובמגבלות התפעול; ציון פלטפורמה כמו Kubeflow אינו מבסס דיוק בחיזוי.

למה אנרגיה היא תחום הפריצה הגדול הבא למהנדסי תוכנה

פריסת סוללות כרוכה באתגרים של ארכיטקטורת מערכות, ממשקי API בעלי השהיה נמוכה, אבטחה ועיבוד נתונים הניתן להרחבה. המאמר אינו מבסס שיא בתפוקת הייצור בארצות הברית, שינוי בצוואר הבקבוק העיקרי של הענף או מחסור מדוד במפתחים. [מקור 1]

תוכנת אנרגיה מחברת מחשוב לתשתית פיזית. אם התחום מעניין אתכם, טלמטריית סוללות ותיאומן מציעות בעיות הנדסיות מוחשיות. ההשפעה על פליטות או על אמינות רשת החשמל תלויה במערכת האנרגיה השלמה ובאופן הפעלתה, לא בתוכנה לבדה.

סיכום והמחשבות שלכם

סקרנו ארכיטקטורה שכבתית לתוכנת סוללות, הדמיית טלמטריה בזיכרון ב־Go, אפשרויות אחסון ותיאום תחנות כוח וירטואליות. הדוגמאות מציגות שאלות תכנון; פריסות בטוחות ואמינות דורשות הגנת חומרה שנבדקה, דרישות תוכנה מפורשות ובדיקת המערכת השלמה.

האם מישהו מכם עבד עם טלמטריית IoT, עם מתווכי MQTT או עם תוכנה לניתוח נתוני סוללות? אילו דפוסים אתם מעדיפים לעיבוד מדדים פיזיים בזמן אמת בלי להתיך את המעבד? ספרו לי בתגובות למטה!

עד הפעם הבאה, המשיכו לתכנת, המשיכו לבנות ושמרו על חוסן המערכות שלכם.

מאמר המקור פורסם ב־SysSeder; המהדורה המתוקנת הזו נבדקה עובדתית ב־27 באוקטובר 2026.

Post a Comment

Previous Post Next Post