Overview
Energy is a critical foundation for civilization and development. From the Stone Age to modern civilization, our energy applications have advanced, but we also face the crisis and fear of energy depletion. Developing and utilizing renewible energy is the primary solution to this challenge. China has been following a practical and sustainable development path in this regard, with every energy enterprise pursuing the development and innovation of new energy sources.
Solar photovoltaic (PV) power generation emerges as a clean, effective, and sustainable high-quality energy source. It addresses issues like energy shortages and continuous supply while ensuring environmental hygiene. The Chinese government has introduced numerous policies and regulations to encourage and support the PV industry, including corporate subsidies and carbon neutrality goals. These have rapidly propelled the PV industry's growth in China, increasing its share in the energy mix and its role in human production and daily life. The prospects for the PV industry are vast, though challenges remain, such as energy density, conversion efficiency, land use, natural impact factors, system costs, and environmentally friendly material production, all of wich are bottlenecks yet to be overcome technologically.
Let's dive straight into the topic.
Introduction
A photovoltaic power generation system consists of solar panels, controllers, inverters, energy storage cabinets, grid connection cabinets, and other major equipment, along with their upper-layer application systems. The process involves design, construction, maintenance, and other important workflows. PV power generation uses the photovoltaic effect of solar cells to convert solar radiation into electricity. The process is simple and environmentally friendly. The main equipment includes:
- Solar Panels: Common panels that generate electricity from sunlight.
- Controller: A core component in off-grid systems that balances the system and protects batteries.
- Inverter: Converts direct current (DC) into alternating current (AC).
- Energy Storage Cabinet: Stores energy.
- Grid Connection Cabinet: A distribution device that feeds generated power into the grid.
- Application System: Uses an IoT+ model to monitor PV equipment status, capture generation data, and effectively dispatch grid power. It combines inverters with data sticks to integrate PV generation, IoT, and information technology, optimizing and innovating from construction to operation and maintenance to minimize manual intervention and achieve full automation.
This article focuses on a distributed PV model, similar to a microgrid, which offers flexibility, compatibility, value, and efficiency. It revolutionizes energy use for enterprises or homes. Installing PV equipment on corporate roofs not only reduces electricity costs but also provides carbon neutrality indicators and helps with roof insulation.
Now, we'll explain the visualization solution for smart PV systems from the application layer, analyzing the PV working principle, PV generation + IoT + visualization model, monitoring PV equipment status, and effectively dispatching microgrid capabilities.
1. Effect Demonstration
1.1 Building-Integrated Photovoltaics (BIPV)
Technological Blue Wireframe Effect

Technological Blue Solid Effect

Scene Switching Code
// Switch scenes
ModelBussiness.prototype.changeSceneModel = function (dataid, _obj) {
const _this = this;
if (_this.currentSceneState === dataid) {
return;
}
modelBussiness.doAnimation = true;
switch (_this.currentSceneState) {
case "bwg":
indexPage.hideCNGChart();
modelBussiness.hideBWGModels(function () {
doModel(dataid);
});
break;
case "nbq":
indexPage.hideGFChart();
modelBussiness.hidewNBQModels(function () {
doModel(dataid);
});
break;
default:
doModel(dataid);
break;
}
_this.currentSceneState = dataid;
function doModel(dataid) {
$("#toolbarBoth").hide();
switch (dataid) {
case "bwg":
indexPage.showCNGChart();
modelBussiness.showBWGModels(function () {
modelBussiness.doAnimation = false;
});
break;
case "nbq":
indexPage.showGFChart();
modelBussiness.showNBQModels(function () {
modelBussiness.doAnimation = false;
});
break;
default:
$("#toolbarBoth").show();
modelBussiness.doAnimation = false;
break;
}
}
}
1.2 PV Equipment Pipeline Topology
Understanding the connection logic through topology helps locate issues.

Chart Panel Creation Code
modelBussiness.chartNames.push(name);
const modelJson = {
id: "",
show: true,
name: name,
objType: "EchartPanel",
position: { x: _obj.position.x, y: 10, z: _obj.position.z + 1 },
showSortNub: 400,
side: 2,
size: { width: 200, height: 100, length: 0 },
echartSize: { width: 1024, height: 512 },
scale: { x: 1, y: 1, z: 1 },
backgroundColor: 0xFFFFFF,
rotation: { x: -0.5236, y: 0, z: 0 },
};
const zlnub = 1;
const option = {
backgroundColor: "#2957A2",
title: {
text: zlnub + "# Grid Cabinet",
textStyle: { color: "#fff" },
left: '2%',
top: '0%'
},
graphic: [
{
type: "text",
left: "2%",
top: "15%",
style: {
text: [
`Status: Charging`,
`SOC: 45%`,
`Current: 34A`,
`Voltage: 220V`,
`Active Power: 345KW`,
`Reactive Power: -0.3kVar`,
`Remaining Capacity: 345kWh`
].join("\n"),
font: "700 14px",
fontSize: 14,
fill: "#fff",
textLineHeight: 14,
}
}
],
tooltip: { trigger: "axis" },
calculable: true,
series: [
{
name: "Max Voltage",
type: "line",
min: 10,
max: 40,
data: [...],
lineStyle: {
normal: {
width: 2,
color: { type: "linear", globalCoord: false },
shadowColor: "rgba(0,255,255, 1)",
shadowBlur: 15,
shadowOffsetY: 0,
},
},
itemStyle: {
normal: {
color: "#AAF487",
borderWidth: 2,
borderColor: "#AAF487",
},
},
smooth: true,
markLine: {
data: [{ type: "average", name: "Average" }],
},
},
],
};
WT3DObj.addEchartPanel(WT3DObj, modelJson, option);
1.3 Grid Connection Cabinet Monitoring
View real-time data and historical curves of grid cabinets.

Data Update Code
if (modelBussiness.chartNames.length >= 0) {
const chartModels = WT3DObj.commonFunc.findObjectsByNames(modelBussiness.chartNames);
$.each(chartModels, function (_index, _chartobj) {
if (_chartobj.name.indexOf("dev_bygcb_") >= 0) {
(function (_obj) {
const dataparam = _obj.name.replace("dev_bygcb_", "").replace("EchartPanel", "");
webapi.getLoadData(dataparam, function (result) {
const newxdata = [];
const newxValues = [];
const data = result.inDays;
$.each(data, function (_di, _do) {
newxdata.push(_do.name);
newxValues.push(_do.value);
});
_obj.myChartOption.xAxis[0].data = newxdata;
_obj.myChartOption.series[0].data = newxValues;
_obj.myChartOption.graphic[0].style.text = [
`Status: ${result.status}`,
`SOC: ${result.soc}`,
`Current: ${result.ia}`,
`Voltage: ${result.ua}`,
`Active Power: ${result.p}`,
`Reactive Power: ${result.q}`,
`Remaining Capacity: ${result.sp}`
].join("\n");
_obj.myChart.setOption(_obj.myChartOption);
_obj.freshData();
});
})(_chartobj);
}
});
}
1.4 Inverter Monitoring
Monitor inverter information.

Inverter Module Code
/*
=============== Inverter Module ===================
*/
ModelBussiness.prototype.showNBQModels = function (callBack) {
const _this = this;
modelBussiness.hideVitureDevs(null, function () {
modelBussiness.doFlashChart = true;
if (callBack) {
callBack();
}
});
WT3DObj.commonFunc.changeCameraPosition(
{ x: -7847.362298856568, y: 2349.326497907068, z: 6092.394946263032 },
{ x: -3839.311641139668, y: 336.68538867317926, z: 896.2806691329519 },
1000,
function () {
setTimeout(function () {
WT3DObj.commonFunc.changeCameraPosition(
{ x: -5823.791307544135, y: 546.2227755970467, z: 1683.797033787011 },
{ x: -5258.110268870251, y: 166.46700423551266, z: 983.0003887760242 },
1000,
function () { }
);
}, 2000);
}
);
}
2. Implementation Logic
2.1 Model Creation
2.1.1 Environment Model

Model Code (Partial)
{
"x": 1,
"y": 0.1,
"z": 1,
"rotation": [
{ "direction": "x", "degree": 0 },
{ "direction": "y", "degree": 0 },
{ "direction": "z", "degree": 0 }
],
"style": {
"skinColor": 16772846,
"imgurl": "../img/3dImg/traffic_01.png",
"opacity": 1,
"canvasSkin": {
"cwidth": 512,
"cheight": 64,
"cwNub": 4,
"chNub": 4,
"cMarginW": 0.2,
"cMarginH": 0.2,
"speed": 8,
"fps": 40,
"direction": "w",
"forward": "f",
"side": 2,
"run": true,
"bgcolor": "rgba(255,102,0,0.07)"
}
},
"segments": 9,
"radialSegments": 4,
"closed": false,
"radius": 40,
"showSortNub": 57
}
2.1.2 Building Model

Building Model Code (Partial)
{
"show": true,
"uuid": "",
"name": "dev_tyn_b1_1",
"objType": "cube2",
"length": 80,
"width": 320,
"height": 5,
"x": 785.461,
"y": 979.498,
"z": 635.388,
"style": {
"skinColor": 16777215,
"skin": {
"skin_up": {
"skinColor": 16777215,
"materialType": "lambert",
"side": 1,
"opacity": 1,
"imgurl": "../img/3dImg/solarBattery4.png",
"repeatx": true,
"width": 2,
"repeaty": true,
"height": 14
},
"skin_down": { "skinColor": 8289918, "side": 1, "opacity": 1 },
"skin_fore": { "skinColor": 2634316, "side": 1, "opacity": 1 },
"skin_behind": { "skinColor": 2634316, "side": 1, "opacity": 1 },
"skin_left": { "skinColor": 2634316, "side": 1, "opacity": 1 },
"skin_right": { "skinColor": 2634316, "side": 1, "opacity": 1 }
}
},
"showSortNub": 68,
"rotation": [
{ "direction": "x", "degree": 3.114138624455922 },
{ "direction": "y", "degree": -0.7853981633974483 },
{ "direction": "z", "degree": 2.7011064569714645 }
]
}
2.1.3 Inverter Model

Inverter Model Code
{
"show": true,
"uuid": "",
"name": "dev_tyn_b2_5",
"objType": "cube2",
"length": 120,
"width": 220,
"height": 5,
"x": 6971.784,
"y": 500,
"z": 1350.98,
"style": {
"skinColor": 16777215,
"skin": {
"skin_up": {
"skinColor": 16777215,
"materialType": "lambert",
"side": 1,
"opacity": 1,
"imgurl": "../img/3dImg/solarBattery4.png",
"repeatx": true,
"width": 4,
"repeaty": true,
"height": 10
},
"skin_down": { "skinColor": 8289918, "side": 1, "opacity": 1 },
"skin_fore": { "skinColor": 2634316, "side": 1, "opacity": 1 },
"skin_behind": { "skinColor": 2634316, "side": 1, "opacity": 1 },
"skin_left": { "skinColor": 2634316, "side": 1, "opacity": 1 },
"skin_right": { "skinColor": 2634316, "side": 1, "opacity": 1 }
}
},
"showSortNub": 68,
"rotation": [
{ "direction": "x", "degree": 0.14289010586077575 },
{ "direction": "y", "degree": 1.5707963267948966 },
{ "direction": "z", "degree": 0 }
]
}
2.1.4 Grid Connection Cabinet Model

Cabinet Model Code
{
"show": true,
"uuid": "",
"name": "dev_byg_2",
"objType": "cube2",
"length": 45,
"width": 100,
"height": 30,
"x": 1751.012,
"y": 50,
"z": 639.269,
"style": {
"skinColor": 16777215,
"skin": {
"skin_up": {
"skinColor": 16777215,
"materialType": "Phong",
"side": 1,
"opacity": 1,
"imgurl": "../img/3dImg/ssn/dypdg1door.jpg"
},
"skin_down": {
"skinColor": 16777215,
"materialType": "Phong",
"side": 1,
"opacity": 1,
"imgurl": "../img/3dImg/ssn/dypdg1ce.jpg"
},
"skin_fore": {
"skinColor": 16777215,
"materialType": "Phong",
"side": 1,
"opacity": 1,
"imgurl": "../img/3dImg/ssn/dypdg1ce.jpg"
},
"skin_behind": {
"skinColor": 16777215,
"materialType": "Phong",
"side": 1,
"opacity": 1,
"imgurl": "../img/3dImg/ssn/dypdg1ce.jpg"
},
"skin_left": {
"skinColor": 16777215,
"materialType": "Phong",
"side": 1,
"opacity": 1,
"imgurl": "../img/3dImg/ssn/dypdg1ding.jpg",
"repeatx": true,
"width": 0.5,
"repeaty": true,
"height": 1
},
"skin_right": {
"skinColor": 16777215,
"materialType": "Phong",
"side": 1,
"opacity": 1,
"imgurl": "../img/3dImg/ssn/dypdg1ding.jpg"
}
}
},
"showSortNub": 167,
"rotation": [
{ "direction": "x", "degree": 1.5707963267948963 },
{ "direction": "y", "degree": 0 },
{ "direction": "z", "degree": 0 }
]
}
2.1.5 Solar Panel Model

This model is simple, using a box with a solar panel texture.
{
"show": true,
"uuid": "",
"name": "dev_tyn_b2_14",
"objType": "cube2",
"length": 120,
"width": 220,
"height": 5,
"x": 7251.596,
"y": 500,
"z": 1068.337,
"style": {
"skinColor": 16777215,
"skin": {
"skin_up": {
"skinColor": 16777215,
"materialType": "lambert",
"side": 1,
"opacity": 1,
"imgurl": "../img/3dImg/solarBattery4.png",
"repeatx": true,
"width": 4,
"repeaty": true,
"height": 10
},
"skin_down": { "skinColor": 8289918, "side": 1, "opacity": 1 },
"skin_fore": { "skinColor": 2634316, "side": 1, "opacity": 1 },
"skin_behind": { "skinColor": 2634316, "side": 1, "opacity": 1 },
"skin_left": { "skinColor": 2634316, "side": 1, "opacity": 1 },
"skin_right": { "skinColor": 2634316, "side": 1, "opacity": 1 }
}
},
"showSortNub": 68,
"rotation": [
{ "direction": "x", "degree": 0.14289010586077575 },
{ "direction": "y", "degree": 1.5707963267948966 },
{ "direction": "z", "degree": 0 }
]
}
2.1.6 Topology Connections

The topology mainly defines pipeline routes. Here is one example:
// Create path
const path = [
{ "x": 0, "y": 0, "z": 0 },
{ "x": 0, "y": 0, "z": -150 },
{ "x": 0, "y": -1, "z": -150 },
{ "x": 0, "y": -250, "z": -150 },
{ "x": -1, "y": -250, "z": -150 },
{ "x": -350, "y": -250, "z": -150 },
{ "x": -350, "y": -250, "z": -149 },
{ "x": -350, "y": -250, "z": 30 },
{ "x": -350, "y": -251, "z": 30 },
{ "x": -350, "y": -680, "z": 30 }
];
const model = {
"show": true,
"uuid": "",
"name": "dev_flowtube_2_3",
"objType": "flowTube",
"points": path,
"position": { "x": 1560.492, "y": 976.703, "z": 605.466 },
"scale": { "x": 1, "y": 1, "z": 1 },
"rotation": [
{ "direction": "x", "degree": 0 },
{ "direction": "y", "degree": 0 },
{ "direction": "z", "degree": 0 }
],
"style": {
"skinColor": 16772846,
"imgurl": "../../img/3dImg/lightL2.png",
"opacity": 1,
"canvasSkin": {
"cwidth": 512,
"cheight": 8,
"cwNub": 16,
"chNub": 2,
"cMarginW": 0.5,
"cMarginH": 0,
"speed": 2,
"fps": 40,
"direction": "w",
"forward": "f",
"side": 1,
"run": true,
"bgcolor": "rgba(0,221,255,0.39)"
}
},
"segments": 9,
"radialSegments": 6,
"closed": false,
"radius": 2,
"showSortNub": 100
};
// Create model
WT3Dobj.createLineByModelJSon(model);
2.2 Data Integration
2.2.1 Create Ajax Request Library
const httpInvoke = function (url, type, data, successCb, failedCb, userData, async) {
return $.ajax({
url: url,
type: type,
data: data,
headers: {},
async: async,
times: 0,
beforeSend: function (request) { },
success: function (response, status, hreq) {
if (response.code === 401) {
// Handle unauthorized
layer.msg('Login expired, please login again.');
window.location.href = '/jigongly/login';
return;
}
if (successCb != null) {
successCb(response, status, userData);
}
},
error: function (err) {
console.log(err);
if (failedCb != null) {
failedCb(err.statusCode(), userData);
}
}
});
}
2.2.2 Create API Repository
function WebAPI() {
this.serverHead = "";
this.serverHead2 = "";
this.urls = {
station: this.serverHead2 + "/station",
airConditioner: this.serverHead2 + "/air",
fireControl: this.serverHead2 + "/fire-ctrl",
pcs: this.serverHead2 + "/pcs",
batteryCabinetBasic: this.serverHead2 + "/battery-basic",
batteryPower: this.serverHead2 + "/battery-power",
powerMonth: this.serverHead2 + "/electric-month",
chargeDischarge: this.serverHead2 + "/dis-charge",
so: this.serverHead2 + "/soc",
profitmonth: this.serverHead2 + "/profit-month",
load: this.serverHead2 + "/load",
surplus: this.serverHead2 + "/surplus-power/",
hostPowerMonth: this.serverHead2 + "/ac/host-power-month",
powerYear: this.serverHead2 + "/ac/power-year",
abstract: this.serverHead2 + "/ac/abstract",
consumptionDay: this.serverHead2 + "/consumption-day/",
chargeDay: this.serverHead2 + "/charge-day/",
temperatures: "../demoData/tempTureData.json",
};
}
Example: Requesting Temperature Data
WebAPI.prototype.TempsCache = {};
WebAPI.prototype.getTemptureValue = function (sunFunc) {
const _this = this;
const url = this.serverHead + this.urls.temperatures + "?positionId=" + _this.roomid;
httpGet(url, function (response) {
if (response && response.data && sunFunc) {
if (response.data.length > 0) {
$.each(response.data, function (_index, _obj) {
_obj.id = _obj.name;
_obj.type = 0;
_obj.temptureValue = _obj.t1MValue;
_obj.temptureValueUp = _obj.t1UValue;
_obj.temptureValueDown = _obj.t1DValue;
_obj.lastUptime = new Date().getTime();
_obj.allBearing = 0;
_this.TempsCache["temp_" + _obj.name] = _obj;
});
}
sunFunc(response.data);
}
}, function () {
layer.msg("Failed to fetch data");
});
}
2.3 Core Logic
2.3.1 Model Creation
As described in the previous sections.
2.3.2 Data Binding to Models
const data = [];
for (let i = 1; i <= 3; i++) {
for (let j = 1; j <= 20; j++) {
let modelname = "dev_cqpdx_" + i + "_" + j;
if (i === 1) {
modelname = "dev_cqpdx_" + j;
}
data.push({
dataId: i + "_" + j,
type: "pdg",
name: modelname,
});
}
}
return data;
2.3.3 Business Logic Implementation
From loading models to instantiation and control:
const T3DModel = new T3D();
const initOption = {
far: 100000000,
antialias: true,
loadSyn: false,
showHelpGrid: false,
clearCoolr: 0x4068b0,
clearColorOp: 0,
};
const Aobjects = {
objects: AllModelJsons,
events: {
dbclick: [
{
obj_name: "ALL",
obj_event: function (_obj, face, objs) {
// Handle double click
}
},
],
mouseDown: [
{
obj_name: "ALL",
obj_event: function (_obj, face, objs) {
// Handle mouse down
}
},
],
mouseMove: [
{
obj_name: "doorLeft",
obj_event: function (_obj, face, objs) {
// Handle mouse move
}
},
]
}
};
WT3DModel.initWT3D('canvas-frame', initOption, Aobjects);
WT3DModel.start();
Due to space constraints, we conclude this lesson here.
The next lesson will focus on implementing 3D energy storage stations and cabinets.