api / scripts /html_to_docx.py
safraeli's picture
Deploy: 2026 sensor migration + redesign + bucket B endpoints
13fc29d verified
"""Convert the solar system electrical plan HTML to a Word document."""
from docx import Document
from docx.shared import Pt, Inches, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
import os
doc = Document()
# โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def set_rtl(paragraph):
"""Set paragraph to RTL."""
pPr = paragraph._p.get_or_add_pPr()
bidi = OxmlElement('w:bidi')
bidi.set(qn('w:val'), '1')
pPr.append(bidi)
paragraph.alignment = WD_ALIGN_PARAGRAPH.RIGHT
def set_cell_rtl(cell):
for p in cell.paragraphs:
set_rtl(p)
def add_heading_rtl(text, level=1):
h = doc.add_heading(text, level=level)
set_rtl(h)
return h
def add_para_rtl(text, bold=False, size=None, color=None):
p = doc.add_paragraph()
set_rtl(p)
run = p.add_run(text)
if bold:
run.bold = True
if size:
run.font.size = Pt(size)
if color:
run.font.color.rgb = color
return p
def add_table_rtl(rows, cols, header_row=None):
table = doc.add_table(rows=rows, cols=cols, style='Table Grid')
table.alignment = WD_TABLE_ALIGNMENT.CENTER
for row in table.rows:
for cell in row.cells:
set_cell_rtl(cell)
return table
def shade_cells(row, color_hex):
"""Shade all cells in a row."""
for cell in row.cells:
shading = OxmlElement('w:shd')
shading.set(qn('w:fill'), color_hex)
shading.set(qn('w:val'), 'clear')
cell._tc.get_or_add_tcPr().append(shading)
def bold_cell(cell, text):
cell.text = ''
p = cell.paragraphs[0]
set_rtl(p)
run = p.add_run(text)
run.bold = True
# โ”€โ”€ Set default font โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
style = doc.styles['Normal']
font = style.font
font.name = 'Arial'
font.size = Pt(11)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• HEADER โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('ืชื›ื ื™ืช ื—ืฉืžืœื™ืช โ€” ืžืขืจื›ืช ืกื•ืœืืจื™ืช ื”ื™ื‘ืจื™ื“ื™ืช', level=0)
add_para_rtl('ื—ื•ื•ืช ื™ืื™ืจ โ€” ืืœื™ ืกืคืจื', bold=True, size=16)
add_para_rtl('ืžืจืฅ 2026 | ืžืžื™ืจ: Solis S6-EH3P20K-H | ืกื•ืœืœื”: CNTE 18.8kWh HV | ืคืื ืœื™ื: 18x620W = 11.16kWp | ื”ืฆืขื”: ืขื•ืฆื (ืื ื˜ืžืŸ) #4027', size=10, color=RGBColor(0x55, 0x55, 0x55))
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• WARNINGS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('ืื–ื”ืจื•ืช ืงืจื™ื˜ื™ื•ืช โ€” ื—ื•ื‘ื” ืœื˜ืคืœ ืœืคื ื™ ื‘ื™ืฆื•ืข', level=1)
warnings = [
'ืžืคืกืง C40 ืงื˜ืŸ ืžื“ื™ ืœืฆื“ ื”ืจืฉืช: ื”ืกื•ืœื™ืก 20K ืžื•ืฉืš ืขื“ 45.6A ืžื”ืจืฉืช. ืžืคืกืง C40 (40A) ื™ืงืคื•ืฅ ื‘ืขื•ืžืก ืžืœื. ื ื“ืจืฉ ืœืคื—ื•ืช C50 ื‘ืฆื“ ื”ืจืฉืช (Grid side).',
'ื‘ื•ืจืจ ืžืฆื‘ื™ื Hager 40A: ื’ื ื”ื‘ื•ืจืจ ืฆืจื™ืš ืœื”ืชืื™ื ืœื–ืจื ื”ืžืงืกื™ืžืœื™ โ€” 40A ืขืœื•ืœ ืœื”ื™ื•ืช ืฆืจ ืžื“ื™. ื™ืฉ ืœืฉืงื•ืœ 63A.',
'DC Isolators ื—ื•ื‘ื”: ืžื ืชืงื™ DC ื™ื™ืขื•ื“ื™ื™ื (ืœื MCB ืฉืœ AC). ื‘ืฆื“ PV: ืžื“ื•ืจื’ 1000Vdc/32A. ื‘ืฆื“ ืกื•ืœืœื”: ืžื“ื•ืจื’ 800Vdc/63A.',
'ืžืขืจืš PV ืงื˜ืŸ ื‘ื™ื—ืก ืœืžืžื™ืจ: 11.16kWp ื”ื ืจืง 35% ืžื”ืžื•ืžืœืฅ ืœ-20K (32kWp). ื”ืžืžื™ืจ ื™ืขื‘ื•ื“, ืื‘ืœ ืœื ื™ื ืฆืœ ืืช ืžืœื•ื ื”ืคื•ื˜ื ืฆื™ืืœ ืฉืœื•.',
'ื”ื”ืฆืขื” ืœื ื›ื•ืœืœืช ื”ืชืงื ืช ืคืื ืœื™ื ืขืœ ื”ื’ื’ โ€” ื‘ืื—ืจื™ื•ืช ื”ืœืงื•ื—. ื ื“ืจืฉ ืงื•ื ืกื˜ืจื•ืงืฆื™ื” ื•ื‘ื™ืกื•ืก.',
]
for w in warnings:
add_para_rtl(f'โš  {w}')
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 1. SYSTEM OVERVIEW โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('1. ืกืงื™ืจืช ื”ืžืขืจื›ืช', level=1)
add_para_rtl('ืžืขืจื›ืช ืกื•ืœืืจื™ืช ื”ื™ื‘ืจื™ื“ื™ืช ืชืœืช-ืคืื–ื™ืช ืขื ื’ื™ื‘ื•ื™ ืกื•ืœืœื”, ื”ืžืืคืฉืจืช ืฆืจื™ื›ื” ืขืฆืžื™ืช, ืื’ื™ืจืช ืื ืจื’ื™ื” ื•ืžืขื‘ืจ ืื•ื˜ื•ืžื˜ื™ ืœืžืฆื‘ ื’ื™ื‘ื•ื™ (UPS) ืชื•ืš ืคื—ื•ืช ืž-10ms ื‘ืขืช ื”ืคืกืงืช ื—ืฉืžืœ.')
# Inverter
add_heading_rtl('ืžืžื™ืจ ื”ื™ื‘ืจื™ื“ื™ โ€” Solis S6-EH3P20K-H', level=2)
add_para_rtl(
'ื”ืกืคืง: 20kW ืชืœืช-ืคืื–ื™\n'
'ืžืชื— ืžืฆื‘ืจ: 120โ€“800V (High Voltage)\n'
'MPPT: 4 ื›ื ื™ืกื•ืช, 200โ€“850V, ืขื“ 20A ืœื›ื ื™ืกื”\n'
'PV ืžื•ืžืœืฅ: ืขื“ 32kWp\n'
'ื™ืขื™ืœื•ืช: 98.5% ืžืงืกื™ืžื•ื, 97.5% EU\n'
'Backup: 20kW, 200% surge ืœ-10 ืฉื ื™ื•ืช\n'
'ื”ื’ื ืช ื›ื ื™ืกื”: IP66\n'
'ืื—ืจื™ื•ืช: 10 ืฉื ื™ื (RCS Solar ื‘ืข"ืž)\n'
'ืžื—ื™ืจ: โ‚ช9,360 (ืœืคื ื™ ืžืข"ืž)'
)
# Battery
add_heading_rtl('ืžืขืจื›ืช ืื’ื™ืจื” โ€” CNTE 18.8kWh HV', level=2)
add_para_rtl(
'ืงื™ื‘ื•ืœืช: 18.8kWh\n'
'ืกื•ื’: LiFePO4 โ€” High Voltage\n'
'ืžืชื— ื ื•ืžื™ื ืœื™: ื˜ื•ื•ื— 120โ€“800V\n'
'ื–ืจื ื˜ืขื™ื ื”/ืคืจื™ืงื” ืžืงืกื™ืžืœื™: 50A\n'
'ื”ื’ื ืช ื›ื ื™ืกื”: IP66 โ€” ืžืชืื™ื ืœื—ื•ืฅ\n'
'ืชืงืฉื•ืจืช: CAN / RS485 ืืœ ื”ืžืžื™ืจ\n'
'ืื—ืจื™ื•ืช: 10 ืฉื ื™ื\n'
'ืžื—ื™ืจ: โ‚ช15,080 (ืœืคื ื™ ืžืข"ืž)'
)
# Panels
add_heading_rtl('ืคืื ืœื™ื ืกื•ืœืืจื™ื™ื โ€” 18 x 620W', level=2)
add_para_rtl(
'ื”ืกืคืง ื›ื•ืœืœ: 11,160Wp (11.16kWp)\n'
'ื—ืœื•ืงื”: 2 ืกื˜ืจื™ื ื’ื™ื x 9 ืคืื ืœื™ื\n'
'Voc ืœืกื˜ืจื™ื ื’: ~396V (ื‘ื˜ื•ื•ื— MPPT)\n'
'Isc ืœืกื˜ืจื™ื ื’: ~18A (ืžืชื—ืช ืœ-20A ืžืงืกื™ืžื•ื)\n'
'ื—ื™ื‘ื•ืจ: MC4\n'
'ืžื—ื™ืจ ืœื™ื—ื™ื“ื”: โ‚ช345\n'
'ืžื—ื™ืจ ื›ื•ืœืœ: โ‚ช6,210 (ืœืคื ื™ ืžืข"ืž)'
)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 2. SINGLE LINE DIAGRAM โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('2. ืชืจืฉื™ื ื—ื“-ืงื•ื•ื™ (Single Line Diagram)', level=1)
add_para_rtl('ืžื‘ื ื” ื”ืžืขืจื›ืช ืžื”ืคืื ืœื™ื ื•ืขื“ ืœืœื•ื— ื”ื—ืฉืžืœื™:')
add_para_rtl('[ื”ืชืจืฉื™ื ื”ื’ืจืคื™ SVG ืœื ื ื™ืชืŸ ืœื”ืžืจื” ืœ-Word โ€” ืจืื” ืงื•ื‘ืฅ HTML ื”ืžืงื•ืจื™ ืœืชืจืฉื™ื ื”ืžืœื]', size=10, color=RGBColor(0x99, 0x99, 0x99))
add_para_rtl(
'String 1: 9x620W = 5,580Wp (Vocโ‰ˆ396V, Iscโ‰ˆ18A, MPPT1)\n'
'String 2: 9x620W = 5,580Wp (Vocโ‰ˆ396V, Iscโ‰ˆ18A, MPPT2)\n'
'โ†“ DC Isolator 1000Vdc/32A (x2)\n'
'โ†“ DC PV Input\n'
'โ†’ Solis S6-EH3P20K-H (Hybrid Inverter, 20kW, 3ฯ†, IP66)\n'
' โ† DC HV โ†’ DC Isolator 800Vdc/63A โ†’ CNTE 18.8kWh Battery (CAN/BMS)\n'
' โ†’ Backup AC (UPS <10ms) โ†’ ABB C40 3P โ†’ ืขื•ืžืกื™ื ื—ื™ื•ื ื™ื™ื\n'
'โ†“ AC Grid Out\n'
'โ†’ CT Sensor โ†’ SPD Type 2 (3P+N, 40kA) โ†’ MCB ABB C50 4P\n'
'โ†’ Hager 4P 40A (ื‘ื•ืจืจ ืžืฆื‘ื™ื)\n'
' โ”œโ†’ MCB ABB C50 4P (Grid) โ†’ ืžื•ื ื” ื™ื™ืฉื•ื‘ โ†’ ืจืฉืช ื—ืฉืžืœ โ†’ ื”ืืจืงื”\n'
' โ””โ†’ MCB ABB C40 4P (Load) โ†’ ืœื•ื— ื—ืฉืžืœื™ (ืขื•ืžืกื™ ื”ื‘ื™ืช)'
)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 3. COMPONENT LIST โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('3. ืจืฉื™ืžืช ืจื›ื™ื‘ื™ื ืžืคื•ืจื˜ืช', level=1)
components = [
('1', 'ืคืื ืœื™ื ืกื•ืœืืจื™ื™ื', '620W โ€” ืžืง"ื˜ s620', '18', 'ื’ื’', '2 ืกื˜ืจื™ื ื’ื™ื x 9'),
('2', 'DC Isolator โ€” PV', '1000Vdc / 32A, 2-pole', '2', 'ืœื™ื“ ื”ืคืื ืœื™ื / ื›ื ื™ืกืช ืžืžื™ืจ', 'ืื—ื“ ืœื›ืœ ืกื˜ืจื™ื ื’'),
('3', 'ืžืžื™ืจ ื”ื™ื‘ืจื™ื“ื™', 'Solis S6-EH3P20K-H', '1', 'ืงื™ืจ ื—ื™ืฆื•ื ื™ ืžื•ืฆืœ', 'IP66 โ€” ืžื•ื’ืŸ ืžื’ืฉื. ืœื”ื’ืŸ ืžืฉืžืฉ ื™ืฉื™ืจื”'),
('4', 'DC Isolator โ€” ืกื•ืœืœื”', '800Vdc / 63A, 2-pole', '1', 'ื‘ื™ืŸ ืžืžื™ืจ ืœืกื•ืœืœื”', 'ืžื“ื•ืจื’ DC!'),
('5', 'ืกื•ืœืœื”', 'CNTE 18.8kWh HV (cnte18.8)', '1', 'ืœื™ื“ ื”ืžืžื™ืจ, ืงื™ืจ ืžื•ืฆืœ', 'IP66 โ€” ื—ื™ืฆื•ื ื™. ืชืงืฉื•ืจืช CAN'),
('6', 'ื—ื™ื™ืฉืŸ ื–ืจื CT', 'Split-core CT, 3-ืคืื–ื™', '1', 'ื‘ื™ืฆื™ืืช AC ืฉืœ ื”ืžืžื™ืจ', 'ืœื ื™ื˜ื•ืจ ื•-zero export'),
('7', 'ืžื’ืŸ ื‘ืจืงื™ื SPD', 'Type 2, 3P+N, 40kA', '1', 'ืื—ืจื™ CT, ืœืคื ื™ ืžืคืกืง ืจืืฉื™', 'ื”ื’ื ื” ืขืœ ืงื• ื™ืฆื™ืืช ืžืžื™ืจ'),
('8', 'ืžืคืกืง ื™ืฆื™ืืช ืžืžื™ืจ', 'ABB C50 4-Pole โš ', '1', 'ืื—ืจื™ SPD', 'ืžืงื•ืจื™ ื‘ื”ืฆืขื” C40 โ€” ืœื ืžืกืคื™ืง!'),
('9', 'ื‘ื•ืจืจ ืžืฆื‘ื™ื', 'Hager 4P 40A', '1', 'ืœืคื ื™ ื”ื”ืชืคืฆืœื•ืช', 'Grid / Solar / Off'),
('10', 'ืžืคืกืง ืจืฉืช', 'ABB C50 4-Pole โš ', '1', 'ืขื ืฃ ืจืฉืช', 'ืฆืจื™ืš C50 ืœื–ืจื 45.6A'),
('11', 'ืžืคืกืง ืขื•ืžืกื™ื', 'ABB C40 4-Pole', '1', 'ืขื ืฃ ืขื•ืžืกื™ ื”ื‘ื™ืช', 'C40 ืžืกืคื™ืง ื›ืืŸ'),
('12', 'ืžืคืกืง ื’ื™ื‘ื•ื™', 'ABB C40 3-Pole', '1', 'ื™ืฆื™ืืช Backup ืฉืœ ืžืžื™ืจ', '3P โ€” ืขื•ืžืกื™ื ื—ื™ื•ื ื™ื™ื ื‘ืœื‘ื“'),
('13', 'ืžื•ื ื” ื™ื™ืฉื•ื‘', 'ืžื•ื ื” ื“ื•-ื›ื™ื•ื•ื ื™ (ืžืกื•ืคืง ืข"ื™ ื”ื™ื™ืฉื•ื‘)', '1', 'ืœืคื ื™ ื”ืจืฉืช', 'โ€”'),
]
table = add_table_rtl(len(components) + 1, 6)
headers = ['#', 'ืจื›ื™ื‘', 'ื“ื’ื / ืžืคืจื˜', 'ื›ืžื•ืช', 'ืžื™ืงื•ื ื‘ืชืจืฉื™ื', 'ื”ืขืจื•ืช']
for i, h in enumerate(headers):
bold_cell(table.rows[0].cells[i], h)
shade_cells(table.rows[0], '0C2340')
for cell in table.rows[0].cells:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_idx, comp in enumerate(components):
for col_idx, val in enumerate(comp):
table.rows[row_idx + 1].cells[col_idx].text = val
set_cell_rtl(table.rows[row_idx + 1].cells[col_idx])
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 4. CABLE SPEC โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('4. ืžืคืจื˜ ื›ื‘ื™ืœื”', level=1)
cables = [
('PV String โ†’ DC Isolator', 'ื›ื‘ืœ ืกื•ืœืืจื™ H1Z2Z2-K', '6mmยฒ (ืื• 4mmยฒ)', 'ืœืคื™ ืžื™ืงื•ื ื’ื’', 'UV-resistant, DC rated, MC4'),
('DC Isolator โ†’ Inverter (PV)', 'ื›ื‘ืœ ืกื•ืœืืจื™ H1Z2Z2-K', '6mmยฒ', '~5m', '+ / โ€“ ืœื›ืœ ืกื˜ืจื™ื ื’'),
('Inverter โ†” Battery', 'ื›ื‘ืœ DC ื’ืžื™ืฉ', '16mmยฒ', '~3m', '50A ืžืงืกื™ืžื•ื. ื“ืจืš ื˜ื‘ืขืช ืžื’ื ื˜ื™ืช x 2 ืœื™ืคื•ืคื™ื'),
('Inverter โ†’ CT โ†’ SPD โ†’ MCB', 'ื›ื‘ืœ AC NYY-J 5G', '10mmยฒ', '~5m', '3L + N + PE, ืชืœืช-ืคืื–ื™'),
('MCB โ†’ Changeover โ†’ Grid/Load', 'ื›ื‘ืœ AC NYY-J 5G', '10mmยฒ', '~10m', 'ืœืคื™ ืžืจื—ืง ืœืœื•ื—'),
('Backup Output โ†’ MCB โ†’ Essential', 'ื›ื‘ืœ AC NYY-J 5G', '6mmยฒ', '~8m', '3P ืœืœื•ื— ืขื•ืžืกื™ื ื—ื™ื•ื ื™ื™ื'),
('ื”ืืจืงื”', 'ื™ืจื•ืง-ืฆื”ื•ื‘', '16mmยฒ (ื ื—ื•ืฉืช)', 'โ€”', 'ื—ื•ื‘ื” โ€” ืžืžื™ืจ + ืกื•ืœืœื” + ืžื‘ื ื”'),
('BMS Communication', 'ื›ื‘ืœ CAN ืžืกื•ื›ืš', 'ืฉื–ื•ืจ', '~3m', 'ื“ืจืš ื˜ื‘ืขืช ืžื’ื ื˜ื™ืช x 4 ืœื™ืคื•ืคื™ื'),
]
table = add_table_rtl(len(cables) + 1, 5)
cable_headers = ['ืงื˜ืข', 'ืกื•ื’ ื›ื‘ืœ', 'ื—ืชืš', 'ืื•ืจืš ืžื•ืขืจืš', 'ื”ืขืจื•ืช']
for i, h in enumerate(cable_headers):
bold_cell(table.rows[0].cells[i], h)
shade_cells(table.rows[0], '0C2340')
for cell in table.rows[0].cells:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_idx, cable in enumerate(cables):
for col_idx, val in enumerate(cable):
table.rows[row_idx + 1].cells[col_idx].text = val
set_cell_rtl(table.rows[row_idx + 1].cells[col_idx])
add_para_rtl('ืฉื™ื ืœื‘: ื›ื‘ืœ ื”ืกื•ืœืœื” ื•ืชืงืฉื•ืจืช BMS ื—ื™ื™ื‘ื™ื ืœืขื‘ื•ืจ ื“ืจืš ื˜ื‘ืขื•ืช ืžื’ื ื˜ื™ื•ืช (ferrite rings) ื›ืคื™ ืฉืžื•ืคื™ืข ื‘ืžืคืจื˜ ื”ืกื•ืœื™ืก โ€” 2 ืœื™ืคื•ืคื™ื ืœื›ื‘ืœ ื—ืฉืžืœ, 4 ืœื™ืคื•ืคื™ื ืœื›ื‘ืœ ืชืงืฉื•ืจืช.', bold=True)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 5. FLOW DESCRIPTION โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('5. ืชื™ืื•ืจ ืžืกืœื•ืœ ื”ื–ืจื', level=1)
add_heading_rtl('ืžืฆื‘ ื™ื•ื โ€” ื™ื™ืฆื•ืจ ืกื•ืœืืจื™', level=2)
day_flow = [
('โ˜€ ืคืื ืœื™ื ืกื•ืœืืจื™ื™ื (2 x 9 = 18 ืคืื ืœื™ื)', 'ืžื™ื™ืฆืจื™ื ื–ืจื DC ื‘ืžืชื— ~360V ืœื›ืœ ืกื˜ืจื™ื ื’, ื“ืจืš ื—ื™ื‘ื•ืจื™ MC4'),
('๐Ÿ”Œ DC Isolators (2 ื™ื—\')', 'ืžื ืชืงื™ ื‘ื˜ื™ื—ื•ืช DC โ€” ืžืืคืฉืจื™ื ื ื™ืชื•ืง ื›ืœ ืกื˜ืจื™ื ื’ ื‘ื ืคืจื“ ืœืชื—ื–ื•ืงื”'),
('INV โ€” Solis 20K โ€” ื”ืžืจื” DCโ†’AC', '4 ื›ื ื™ืกื•ืช MPPT (200-850V). ืžืžื™ืจ ืืช ื”ื–ืจื ืœ-AC ืชืœืช-ืคืื–ื™ 400V/50Hz. ื‘ืžืงื‘ื™ืœ ื˜ื•ืขืŸ ืืช ื”ืกื•ืœืœื” ืžืขื•ื“ืคื™ ื™ื™ืฆื•ืจ'),
('CT ื—ื™ื™ืฉืŸ ื–ืจื', 'ืžื•ื“ื“ ืืช ื”ื–ืจื ื‘ื™ืฆื™ืื” ืœืฆื•ืจืš ื ื™ื˜ื•ืจ, ืื™ื–ื•ืŸ ืคืื–ื•ืช ื•ืžื ื™ืขืช ื”ื–ืจืžื” ืœืจืฉืช (zero export ืื ื ื“ืจืฉ)'),
('โšก SPD ืžื’ืŸ ื‘ืจืงื™ื Type 2', 'ื”ื’ื ืช ื ื—ืฉื•ืœื™ ืžืชื— (surge) ืขืœ ืงื• AC ื”ื™ื•ืฆื ืžื”ืžืžื™ืจ. 3P+N, ืขื“ 40kA'),
('๐Ÿ”„ ื‘ื•ืจืจ ืžืฆื‘ื™ื Hager 4P 40A', 'ืžืืคืฉืจ ืžืขื‘ืจ ื™ื“ื ื™ ื‘ื™ืŸ: ืจืฉืช + ืกื•ืœืืจื™ | ืกื•ืœืืจื™ ื‘ืœื‘ื“ | ื ื™ืชื•ืง ืžืœื'),
('๐Ÿ  ืœื•ื— ื—ืฉืžืœื™ ื”ื‘ื™ืช', 'ืขื•ืžืกื™ ื”ื‘ื™ืช ืžืงื‘ืœื™ื ื—ืฉืžืœ ืžื”ืกื•ืœืืจื™. ืขื•ื“ืคื™ื โ†’ ืกื•ืœืœื” โ†’ ืจืฉืช (ืœืคื™ ื”ื’ื“ืจื”)'),
]
for title, desc in day_flow:
p = doc.add_paragraph()
set_rtl(p)
run = p.add_run(f'{title}: ')
run.bold = True
p.add_run(desc)
add_heading_rtl('ืžืฆื‘ ืœื™ืœื” / ื”ืคืกืงืช ื—ืฉืžืœ', level=2)
night_flow = [
('๐Ÿ”‹ CNTE 18.8kWh', 'ื”ืกื•ืœืœื” ืžืกืคืงืช ื–ืจื DC HV ืœืžืžื™ืจ'),
('INV โ€” Solis 20K โ€” ื”ืžืจื” DCโ†’AC', 'ืžืžื™ืจ ืœ-AC ื•ืžืกืคืง ืœืขื•ืžืกื™ื. ืžืขื‘ืจ UPS ืื•ื˜ื•ืžื˜ื™ ืชื•ืš <10ms'),
('๐Ÿ  ืขื•ืžืกื™ื ื—ื™ื•ื ื™ื™ื (Backup port)', 'ืžืงืจืจ, ืชืื•ืจื”, ืจืื•ื˜ืจ โ€” ืžืžื•ื–ื ื™ื ื™ืฉื™ืจื•ืช ืžื™ืฆื™ืืช ื”-Backup ืœืœื ื”ืคืกืงื”'),
]
for title, desc in night_flow:
p = doc.add_paragraph()
set_rtl(p)
run = p.add_run(f'{title}: ')
run.bold = True
p.add_run(desc)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 6. INVERTER SPECS โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('6. ืžืคืจื˜ ืžืžื™ืจ Solis S6-EH3P20K-H', level=1)
specs_sections = [
('ื›ื ื™ืกืช DC โ€” ืคื•ื˜ื•-ื•ื•ืœื˜ืื™', [
('PV ืžื•ืžืœืฅ ืžืงืกื™ืžืœื™', '32kWp'),
('ืžืชื— ืžืงืกื™ืžืœื™', '1000V'),
('ื˜ื•ื•ื— MPPT', '200โ€“850V'),
('ื–ืจื ืžืงืกื™ืžืœื™ ืœื›ื ื™ืกื”', '20A x 4'),
('ืžืกืคืจ MPPT / ืกื˜ืจื™ื ื’ื™ื', '4/4'),
('ื”ืกืคืง ืžืงืกื™ืžืœื™ ืœ-MPPT', '9kW'),
]),
('ื›ื ื™ืกืช / ื™ืฆื™ืืช ืกื•ืœืœื”', [
('ืกื•ื’', 'Li-ion (High Voltage)'),
('ื˜ื•ื•ื— ืžืชื—', '120โ€“800V'),
('ื”ืกืคืง ื˜ืขื™ื ื”/ืคืจื™ืงื” ืžืงืกื™ืžืœื™', '20kW'),
('ื–ืจื ืžืงืกื™ืžืœื™', '50A'),
('ืชืงืฉื•ืจืช', 'CAN / RS485'),
]),
('ื™ืฆื™ืืช AC โ€” ืจืฉืช', [
('ื”ืกืคืง ื™ืฆื™ืื”', '20kW / 20kVA'),
('ืžืชื—', '3/N/PE, 380V/400V'),
('ื–ืจื ื™ืฆื™ืื” ืžืงืกื™ืžืœื™', '30.4A / 28.9A'),
('Power Factor', '>0.99'),
('THDi', '<3%'),
]),
('ื›ื ื™ืกืช AC โ€” ืจืฉืช', [
('ื”ืกืคืง ื›ื ื™ืกื” ืžืงืกื™ืžืœื™', '30kW'),
('ื–ืจื ื›ื ื™ืกื”', '45.6A โš '),
('ืžืชื—', '3/N/PE, 380V/400V'),
('ืชื“ืจ', '50Hz / 60Hz'),
]),
('ื™ืฆื™ืืช Backup', [
('ื”ืกืคืง', '20kW'),
('Surge', '200% ืœืžืฉืš 10 ืฉื ื™ื•ืช (40kW!)'),
('ื–ืžืŸ ืžืขื‘ืจ', '<10ms'),
('ืžืชื—', '3/N/PE, 380V/400V'),
]),
('ื›ืœืœื™', [
('ื™ืขื™ืœื•ืช ืžืงืกื™ืžืœื™ืช', '98.5%'),
('ื™ืขื™ืœื•ืช EU', '97.5%'),
('ื”ื’ื ืช ื›ื ื™ืกื”', 'IP66'),
('ื˜ืžืคืจื˜ื•ืจืช ืขื‘ื•ื“ื”', '-25ยฐC ืขื“ +60ยฐC'),
('ืžื™ื“ื•ืช', '563x546x235 ืž"ืž'),
('ืงื™ืจื•ืจ', 'ืžืื•ื•ืจืจ ืื™ื ื˜ืœื™ื’ื ื˜ื™ ื›ืคื•ืœ'),
]),
]
for section_title, specs in specs_sections:
add_heading_rtl(section_title, level=2)
table = add_table_rtl(len(specs), 2)
for row_idx, (key, val) in enumerate(specs):
bold_cell(table.rows[row_idx].cells[0], key)
table.rows[row_idx].cells[1].text = val
set_cell_rtl(table.rows[row_idx].cells[1])
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 7. PRICING โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('7. ืคื™ืจื•ื˜ ืขืœื•ื™ื•ืช โ€” ื”ืฆืขืช ืขื•ืฆื (ืื ื˜ืžืŸ) #4027', level=1)
pricing = [
('ืžืžื™ืจ Solis 20kW', 'solis20k', '1', 'โ‚ช9,360', 'โ‚ช9,360'),
('ืงื™ื˜ ื‘ื˜ืจื™ื•ืช CNTE 18.8kWh', 'cnte18.8', '1', 'โ‚ช15,080', 'โ‚ช15,080'),
('ืœื•ื— ืกื•ืœืืจื™ 620W', 's620', '18', 'โ‚ช345', 'โ‚ช6,210'),
('ื”ืชืงื ื” ืœืžืžื™ืจ ื•ืžืฆื‘ืจื™ื', 'โ€”', '1', 'โ‚ช5,800', 'โ‚ช5,800'),
]
table = add_table_rtl(len(pricing) + 4, 5)
price_headers = ['ืคืจื™ื˜', 'ืžืง"ื˜', 'ื›ืžื•ืช', 'ืžื—ื™ืจ ื™ื—ื™ื“ื”', 'ืกื”"ื›']
for i, h in enumerate(price_headers):
bold_cell(table.rows[0].cells[i], h)
shade_cells(table.rows[0], '0C2340')
for cell in table.rows[0].cells:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_idx, item in enumerate(pricing):
for col_idx, val in enumerate(item):
table.rows[row_idx + 1].cells[col_idx].text = val
set_cell_rtl(table.rows[row_idx + 1].cells[col_idx])
# Subtotal
subtotal_row = len(pricing) + 1
bold_cell(table.rows[subtotal_row].cells[0], 'ืกื”"ื› ืœืคื ื™ ืžืข"ืž')
table.rows[subtotal_row].cells[0].merge(table.rows[subtotal_row].cells[3])
bold_cell(table.rows[subtotal_row].cells[4], 'โ‚ช36,450')
shade_cells(table.rows[subtotal_row], 'F0F4FF')
# VAT
vat_row = subtotal_row + 1
table.rows[vat_row].cells[0].text = 'ืžืข"ืž 18%'
set_cell_rtl(table.rows[vat_row].cells[0])
table.rows[vat_row].cells[0].merge(table.rows[vat_row].cells[3])
table.rows[vat_row].cells[4].text = 'โ‚ช6,561'
set_cell_rtl(table.rows[vat_row].cells[4])
# Total
total_row = vat_row + 1
bold_cell(table.rows[total_row].cells[0], 'ืกื”"ื› ื›ื•ืœืœ ืžืข"ืž')
table.rows[total_row].cells[0].merge(table.rows[total_row].cells[3])
bold_cell(table.rows[total_row].cells[4], 'โ‚ช43,011')
shade_cells(table.rows[total_row], '0C2340')
for cell in [table.rows[total_row].cells[0], table.rows[total_row].cells[4]]:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
run.font.size = Pt(14)
add_para_rtl('ืœื ื›ืœื•ืœ ื‘ื”ืฆืขื”: ื”ืชืงื ื” ืคื™ื–ื™ืช ืฉืœ ื”ืคืื ืœื™ื ืขืœ ื”ื’ื’ (ืงื•ื ืกื˜ืจื•ืงืฆื™ื”, ื”ื’ื‘ื”ื•ืช, ื‘ื™ืกื•ืก) โ€” ื‘ืื—ืจื™ื•ืช ื”ืœืงื•ื— ืื• ืงื‘ืœืŸ ื ื•ืกืฃ.', bold=True, color=RGBColor(0xC6, 0x28, 0x28))
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 8. INSTALLATION NOTES โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('8. ื”ื ื—ื™ื•ืช ื”ืชืงื ื”', level=1)
add_heading_rtl('ืžื™ืงื•ื ืžืžื™ืจ ื•ืกื•ืœืœื”', level=2)
add_para_rtl('ืฉื ื™ ื”ืจื›ื™ื‘ื™ื (Solis + CNTE) ื‘ืขืœื™ ื“ื™ืจื•ื’ IP66 ื•ืžืชืื™ืžื™ื ืœื”ืชืงื ื” ื—ื™ืฆื•ื ื™ืช. ื™ืฉ ืœืžืงื ืื•ืชื:')
for item in [
'ืขืœ ืงื™ืจ ืžื•ืฆืœ โ€” ื‘ืื—ืจื™ื•ืช ื”ืœืงื•ื— ืœื”ื’ืŸ ืžืคื ื™ ืฉืžืฉ ื™ืฉื™ืจื” (ื›ืคื™ ืฉืžืฆื•ื™ืŸ ื‘ื”ืฆืขื”)',
'ื’ื•ื‘ื” ืžื™ื ื™ืžืœื™ 60 ืก"ืž ืžื”ืงืจืงืข (ื”ืฆืคื”, ืžื–ื™ืงื™ื)',
'ืžืจื•ื•ื— ืื•ื•ืจื•ืจ: ืœืคื—ื•ืช 30 ืก"ืž ืžื›ืœ ืฆื“, 50 ืก"ืž ืžืœืžืขืœื”',
'ื ื’ื™ืฉ ืœืชื—ื–ื•ืงื” โ€” DC Isolators ื‘ื”ื™ืฉื’ ื™ื“',
]:
add_para_rtl(f'โ€ข {item}')
add_heading_rtl('ื”ืืจืงื”', level=2)
add_para_rtl('ื—ื•ื‘ื” ืœื‘ืฆืข ื”ืืจืงื” ืชืงื ื™ืช ืœื›ืœ ื”ืจื›ื™ื‘ื™ื: ื’ื•ืฃ ื”ืžืžื™ืจ, ื’ื•ืฃ ื”ืกื•ืœืœื”, ืžื‘ื ื” ื”ืงื•ื ืกื˜ืจื•ืงืฆื™ื” ืฉืœ ื”ืคืื ืœื™ื, ื•ืžืกื’ืจื•ืช ื”ืคืื ืœื™ื ืขืฆืžื. ื—ืชืš ืžื™ื ื™ืžืœื™: 16mmยฒ ื ื—ื•ืฉืช.')
add_heading_rtl('ื—ื™ื‘ื•ืจ ืกื•ืœืœื”', level=2)
add_para_rtl('ื›ื‘ืœ DC ืœืกื•ืœืœื” ื—ื™ื™ื‘ ืœืขื‘ื•ืจ ื“ืจืš ื˜ื‘ืขืช ืžื’ื ื˜ื™ืช (ferrite ring) ืขื 2 ืœื™ืคื•ืคื™ื. ื›ื‘ืœ ืชืงืฉื•ืจืช CAN/BMS โ€” ื“ืจืš ื˜ื‘ืขืช ืžื’ื ื˜ื™ืช ืขื 4 ืœื™ืคื•ืคื™ื. ืžื•ืžื ื˜ ื”ื™ื“ื•ืง ืœืžื—ื‘ืจ: 24.5 Nยทm.')
add_heading_rtl('ืื—ืจื™ื•ืช ื•ืฉื™ืจื•ืช', level=2)
add_para_rtl('ืœืคื™ ื”ืฆืขืช ืขื•ืฆื (ืื ื˜ืžืŸ):')
for item in [
'Solis โ€” ืฉื™ืจื•ืช ื•ืื—ืจื™ื•ืช: ืืจ ืกื™ ืืก ืกื•ืœืืจ ื‘ืข"ืž (RCS Solar)',
'CNTE / Yoshopo โ€” ืฉื™ืจื•ืช ื•ืื—ืจื™ื•ืช: ืืจ ืกื™ ืืก ืกื•ืœืืจ ื‘ืข"ืž',
'ืื—ืจื™ื•ืช: 10 ืฉื ื™ื ืขืœ ืžืžื™ืจ ื•ืกื•ืœืœื”',
]:
add_para_rtl(f'โ€ข {item}')
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 9. QA REVIEW โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('9. ื‘ืงืจืช ืื™ื›ื•ืช โ€” ืžืžืฆืื™ื ื•ืชื™ืงื•ื ื™ื', level=1)
add_para_rtl('ืกืงื™ืจื” ืžืงืฆื•ืขื™ืช ืฉืœ ื”ืชื›ื ื™ืช ื–ื™ื”ืชื” ืืช ื”ื ืงื•ื“ื•ืช ื”ื‘ืื•ืช. ื™ืฉ ืœื˜ืคืœ ื‘ื›ื•ืœืŸ ืœืคื ื™ ืชื—ื™ืœืช ื‘ื™ืฆื•ืข:')
# Critical findings
add_heading_rtl('ืžืžืฆืื™ื ืงืจื™ื˜ื™ื™ื (ื—ื•ื‘ื” ืœืชืงืŸ)', level=2)
critical = [
('Q1', 'ื“ื™ืจื•ื’ ืžืคืกืงื™ AC', 'Solis 20K โ€” ื–ืจื ื›ื ื™ืกื” ืžืจืฉืช ืขื“ 45.6A. ืžืคืกืง C40 (40A) ื™ืงืคื•ืฅ ื‘ืขื•ืžืก ืžืœื. ื”ื’ื ื” ืœื ืชืงื™ื ื”', 'ืœื”ื—ืœื™ืฃ ืœ-C50 (50A) ื‘ืฆื“ ื™ืฆื™ืืช ืžืžื™ืจ ื•ื‘ืฆื“ ื”ืจืฉืช. ืžืคืกืง ืขื•ืžืกื™ื (C40) โ€” ืชืงื™ืŸ'),
('Q2', 'ื‘ื•ืจืจ ืžืฆื‘ื™ื โ€” ื“ื™ืจื•ื’ ื–ืจื', 'Hager 40A ืขืœื•ืœ ืœื”ื™ื•ืช ืงื˜ืŸ ืžื“ื™. ื–ืจื ืžืงืกื™ืžืœื™ ืขื•ื‘ืจ ื“ืจื›ื• (ืขื“ 45.6A ืžืจืฉืช + ื™ื™ืฆื•ืจ ืกื•ืœืืจื™)', 'ืœืฉืงื•ืœ ืฉื“ืจื•ื’ ืœ-Hager 63A 4P, ืื• ืœื•ื•ื“ื ืฉืชืจื—ื™ืฉ ื”ืขื•ืžืก ื”ืžืงืกื™ืžืœื™ ืœื ื—ื•ืจื’ ืž-40A'),
('Q3', 'ื”ื’ื ืช ืคื—ืช (RCD/RCBO) ื—ืกืจื”', 'ื”ืชื›ื ื™ืช ืœื ื›ื•ืœืœืช ื”ื’ื ืช ืคื—ืช โ€” ื–ืœื™ื’ืช ื–ืจื ืœื’ื•ืฃ ืื“ื ืœื ืชื’ืจื•ื ืœื ื™ืชื•ืง', 'ืœื”ื•ืกื™ืฃ RCD Type A ื‘ื“ื™ืจื•ื’ 30mA ื‘ืฆื“ AC, ืœืคื ื™ ืœื•ื— ื”ืขื•ืžืกื™ื. ื—ืœืง ืžื”ืžืžื™ืจื™ื Transformerless ื“ื•ืจืฉื™ื RCD Type B โ€” ืœื•ื•ื“ื ืžื•ืœ ืžืคืจื˜ ื”ืกื•ืœื™ืก'),
('Q4', 'ืžืคืกืง Backup โ€” ืžืกืคืจ ืงื˜ื‘ื™ื', 'ืžืคืกืง 3P (3 ืงื˜ื‘ื™ื) ืœื ืžื’ืŸ ืขืœ Neutral. ื™ืฆื™ืืช Backup ืฉืœ ื”ืกื•ืœื™ืก ื”ื™ื 3/N/PE', 'ืœื”ื—ืœื™ืฃ ืœ-ABB C40 4P (4 ืงื˜ื‘ื™ื) ื’ื ื‘ืขื ืฃ ื”-Backup'),
]
table = add_table_rtl(len(critical) + 1, 4)
for i, h in enumerate(['#', 'ืžืžืฆื', 'ื‘ืขื™ื”', 'ืชื™ืงื•ืŸ ื ื“ืจืฉ']):
bold_cell(table.rows[0].cells[i], h)
shade_cells(table.rows[0], '0C2340')
for cell in table.rows[0].cells:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_idx, item in enumerate(critical):
for col_idx, val in enumerate(item):
table.rows[row_idx + 1].cells[col_idx].text = val
set_cell_rtl(table.rows[row_idx + 1].cells[col_idx])
shade_cells(table.rows[row_idx + 1], 'FFF8E1')
# Important findings
add_heading_rtl('ืžืžืฆืื™ื ื—ืฉื•ื‘ื™ื (ืžื•ืžืœืฅ ืœืชืงืŸ)', level=2)
important = [
('Q5', 'AFCI โ€” ื”ื’ื ืช ืงืฉืช ื—ืฉืžืœื™ืช', 'ื”ืกื•ืœื™ืก ื›ื•ืœืœ AFCI ืžื•ื‘ื ื” ื‘ืฆื“ DC, ืืš ื“ื•ืจืฉ ื”ืคืขืœื” ื™ื“ื ื™ืช (activation required)', 'ืœื•ื•ื“ื ืฉื”ื—ืฉืžืœืื™ ืžืคืขื™ืœ ืืช AFCI ื‘ื”ื’ื“ืจื•ืช ื”ืžืžื™ืจ ื‘ืขืช ื”ื”ืชืงื ื”'),
('Q6', 'SPD ื‘ืฆื“ DC ื—ืกืจ', 'ื”ืชื›ื ื™ืช ื›ื•ืœืœืช SPD ื‘ืฆื“ AC ื‘ืœื‘ื“. ืคืื ืœื™ื ืขืœ ื”ื’ื’ ื—ืฉื•ืคื™ื ืœืคื’ื™ืขืช ื‘ืจืง ื™ืฉื™ืจื” ื‘ืฆื“ DC', 'ืœื”ื•ืกื™ืฃ SPD Type 2 DC ืžื“ื•ืจื’ 1000Vdc ื‘ื™ืŸ ื”ืคืื ืœื™ื ืœ-DC Isolator, ืื• ืœื™ื“ ื›ื ื™ืกืช PV ื‘ืžืžื™ืจ'),
('Q7', 'ื—ืชืš ื›ื‘ืœ AC โ€” ืžืจื•ื•ื— ืฆืจ', 'ื›ื‘ืœ NYY-J 5G10 ืžื“ื•ืจื’ ืœ-~57A ื‘ืื•ื•ื™ืจ. ืขื‘ื•ืจ 45.6A ื–ื”ื• ื ื™ืฆื•ืœ ืฉืœ 80% โ€” ืชืงื™ืŸ, ืืš ืœืœื ืžืจื•ื•ื— ืœืขืœื™ื™ืช ื˜ืžืคืจื˜ื•ืจื”', 'ืื ืžืกืœื•ืœ ื”ื›ื‘ืœ ื—ื (ืฆื™ื ื•ืจ ื‘ืฉืžืฉ, ืจื™ื›ื•ื– ื›ื‘ืœื™ื) โ€” ืœืฉืงื•ืœ ืฉื“ืจื•ื’ ืœ-5G16. ืื—ืจืช, 5G10 ืžืกืคื™ืง'),
('Q8', 'ื˜ื‘ืขื•ืช ืžื’ื ื˜ื™ื•ืช (Ferrite) ื—ืกืจื•ืช ืžืจืฉื™ืžืช ืจื›ื™ื‘ื™ื', 'ืžื•ื–ื›ืจื•ืช ื‘ื”ื ื—ื™ื•ืช ื›ื‘ื™ืœื” ืืš ืœื ื‘ืจืฉื™ืžืช ื”ืจื›ื™ื‘ื™ื โ€” ืขืœื•ืœื•ืช ืœื”ื™ืฉื›ื— ื‘ืจื›ืฉ', 'ืœื”ื•ืกื™ืฃ ืœืจืฉื™ืžื”: 2 ื˜ื‘ืขื•ืช ืžื’ื ื˜ื™ื•ืช โ€” ืื—ืช ืœื›ื‘ืœ DC ืกื•ืœืœื”, ืื—ืช ืœื›ื‘ืœ BMS'),
('Q9', 'ื—ืกืจ: ื”ื’ื“ืจืช ืžืฆื‘ ืขื‘ื•ื“ื” โ€” net metering / zero export', 'ื”ืชื›ื ื™ืช ืœื ืžืฆื™ื™ื ืช ืื ื”ืžืขืจื›ืช ืขื•ื‘ื“ืช ื‘ืžืฆื‘ net metering (ื”ื–ืจืžื” ืœืจืฉืช) ืื• zero export. ื–ื” ืžืฉืคื™ืข ืขืœ ืชืฆื•ืจืช CT', 'ืœื”ื’ื“ื™ืจ ืžื•ืœ ื”ื™ื™ืฉื•ื‘: ื”ืื ืžื•ืชืจ ืœืžื›ื•ืจ ื—ืฉืžืœ ืœืจืฉืช? ืื ืœื โ€” ืœื”ื’ื“ื™ืจ CT ืœืžืฆื‘ zero export ื‘ืžืžื™ืจ'),
]
table = add_table_rtl(len(important) + 1, 4)
for i, h in enumerate(['#', 'ืžืžืฆื', 'ื‘ืขื™ื”', 'ืชื™ืงื•ืŸ ื ื“ืจืฉ']):
bold_cell(table.rows[0].cells[i], h)
shade_cells(table.rows[0], '0C2340')
for cell in table.rows[0].cells:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_idx, item in enumerate(important):
for col_idx, val in enumerate(item):
table.rows[row_idx + 1].cells[col_idx].text = val
set_cell_rtl(table.rows[row_idx + 1].cells[col_idx])
# Verified OK
add_heading_rtl('ืชืงื™ืŸ โ€” ืื•ืžืช', level=2)
verified = [
('Voc ืกื˜ืจื™ื ื’', '9 x ~44V = 396V < 1000V (ืžืงืกื™ืžื•ื), ื‘ืชื•ืš 200โ€“850V (MPPT)', 'ืชืงื™ืŸ โœ“'),
('Isc ืกื˜ืจื™ื ื’', '~18A < 20A (ืžืงืกื™ืžื•ื ืœื›ื ื™ืกืช MPPT), < 30A (ืงืฆืจ)', 'ืชืงื™ืŸ โœ“'),
('ื”ืชืืžืช ืกื•ืœืœื”', 'CNTE HV โ€” ื˜ื•ื•ื— 120โ€“800V ืชื•ืื ืœืกื•ืœื™ืก (120โ€“800V)', 'ืชืงื™ืŸ โœ“'),
('ื–ืจื ืกื•ืœืœื”', '50A ืžืงืกื™ืžื•ื โ€” ืชื•ืื ืœืกื•ืœื™ืก (50A max charge/discharge)', 'ืชืงื™ืŸ โœ“'),
('IP Rating', 'ืžืžื™ืจ IP66 + ืกื•ืœืœื” IP66 โ€” ืžืชืื™ื ืœื”ืชืงื ื” ื—ื™ืฆื•ื ื™ืช ื‘ื—ื•ื•ืช ื™ืื™ืจ', 'ืชืงื™ืŸ โœ“'),
('ืชืงืฉื•ืจืช BMS', 'CAN/RS485 โ€” ืชื•ืื ื‘ื™ืŸ CNTE ืœืกื•ืœื™ืก', 'ืชืงื™ืŸ โœ“'),
('ืžืคืกืง ืขื•ืžืกื™ื', 'C40 ื‘ืขื ืฃ ืขื•ืžืกื™ ื”ื‘ื™ืช โ€” ืชืงื™ืŸ (ื–ืจื ื™ืฆื™ืืช ืžืžื™ืจ 30.4A)', 'ืชืงื™ืŸ โœ“'),
('DC Switch ืžื•ื‘ื ื”', 'ื”ืกื•ืœื™ืก ื›ื•ืœืœ DC Switch ืžื•ื‘ื ื” (integrated) โ€” ืชื•ืื ืœืชืงืŸ', 'ืชืงื™ืŸ โœ“'),
('ืžื•ืžื ื˜ ื”ื™ื“ื•ืง ืกื•ืœืœื”', '24.5 Nยทm โ€” ืชื•ืื ืžืคืจื˜ (M8)', 'ืชืงื™ืŸ โœ“'),
('ื—ื™ืฉื•ื‘ ืขืœื•ื™ื•ืช', 'โ‚ช36,450 + 18% = โ‚ช43,011', 'ืชืงื™ืŸ โœ“'),
]
table = add_table_rtl(len(verified) + 1, 3)
for i, h in enumerate(['ืคืจื™ื˜', 'ื‘ื“ื™ืงื”', 'ืชื•ืฆืื”']):
bold_cell(table.rows[0].cells[i], h)
shade_cells(table.rows[0], '0C2340')
for cell in table.rows[0].cells:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_idx, item in enumerate(verified):
for col_idx, val in enumerate(item):
table.rows[row_idx + 1].cells[col_idx].text = val
set_cell_rtl(table.rows[row_idx + 1].cells[col_idx])
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 10. EXECUTION GUIDELINES โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('10. ื”ื ื—ื™ื•ืช ื‘ื™ืฆื•ืข โ€” ืฉืœื‘ ืื—ืจ ืฉืœื‘', level=1)
add_para_rtl('ื›ืœืœ ื‘ืจื–ืœ: ื›ืœ ื”ืขื‘ื•ื“ื” ื”ื—ืฉืžืœื™ืช ื—ื™ื™ื‘ืช ืœื”ืชื‘ืฆืข ืขืœ ื™ื“ื™ ื—ืฉืžืœืื™ ืžื•ืกืžืš ื‘ืขืœ ืจื™ืฉื™ื•ืŸ ื‘ืชื•ืงืฃ. ืขื‘ื•ื“ื” ืขืœ ืžืชื— DC ื’ื‘ื•ื” (ืขื“ 800V) ืžืกื•ื›ื ืช โ€” ืœื ืœื’ืขืช ื‘ืœื™ ืฆื™ื•ื“ ืžื’ืŸ ืžืชืื™ื.', bold=True, color=RGBColor(0xC6, 0x28, 0x28))
# Phase A
def add_checklist_table(title, items):
add_heading_rtl(title, level=2)
table = add_table_rtl(len(items) + 1, 3)
for i, h in enumerate(['โ˜', 'ืžืฉื™ืžื”', 'ืคื™ืจื•ื˜']):
bold_cell(table.rows[0].cells[i], h)
shade_cells(table.rows[0], '0C2340')
for cell in table.rows[0].cells:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_idx, (task, detail) in enumerate(items):
table.rows[row_idx + 1].cells[0].text = 'โ˜'
set_cell_rtl(table.rows[row_idx + 1].cells[0])
bold_cell(table.rows[row_idx + 1].cells[1], task)
table.rows[row_idx + 1].cells[2].text = detail
set_cell_rtl(table.rows[row_idx + 1].cells[2])
add_checklist_table('ืฉืœื‘ ื\' โ€” ื”ื›ื ื” ื•ืจื›ืฉ (ืœืคื ื™ ืชื—ื™ืœืช ืขื‘ื•ื“ื”)', [
('ืื™ืฉื•ืจ ืชื›ื ื™ืช ืžื•ืœ ื—ืฉืžืœืื™', 'ืœื”ืขื‘ื™ืจ ืชื›ื ื™ืช ื–ื• ืœื—ืฉืžืœืื™ ืžื•ืกืžืš ืœืื™ืฉื•ืจ. ืœื•ื•ื“ื ื”ืชืืžื” ืœืชืงื ื•ืช ื—ืฉืžืœ ื™ืฉืจืืœื™ื•ืช ื•ืœื“ืจื™ืฉื•ืช ื”ื™ื™ืฉื•ื‘'),
('ื‘ื™ืจื•ืจ ืžื•ืœ ื”ื™ื™ืฉื•ื‘', 'ื”ืื ืžื•ืชืจ net metering (ืžื›ื™ืจืช ื—ืฉืžืœ)? ืžื”ื ื“ืจื™ืฉื•ืช ื”ื—ื™ื‘ื•ืจ? ื”ืื ื ื“ืจืฉ ืื™ืฉื•ืจ ื•ืขื“ืช ืชื›ื ื•ืŸ?'),
('ืจื›ืฉ ืจื›ื™ื‘ื™ื ื—ืกืจื™ื', 'ืžืคืกืงื™ ABB C50 4P (x2), ABB C40 4P (x2 โ€” ืขื•ืžืกื™ื + backup), SPD AC Type 2, SPD DC Type 2, DC Isolators (x3), RCD Type A 30mA, ื˜ื‘ืขื•ืช ืžื’ื ื˜ื™ื•ืช (x2), ื‘ื•ืจืจ ืžืฆื‘ื™ื Hager 63A 4P'),
('ืจื›ืฉ ื›ื‘ืœื™ื', 'ื›ื‘ืœ ืกื•ืœืืจื™ H1Z2Z2-K 6mmยฒ (ืœืคื™ ืžื“ื™ื“ืช ืื•ืจืš), NYY-J 5G10 (ืื• 5G16), ื›ื‘ืœ DC 16mmยฒ ืœืกื•ืœืœื”, ื›ื‘ืœ CAN ืžืกื•ื›ืš, ื›ื‘ืœ ื”ืืจืงื” 16mmยฒ ื™ืจื•ืง-ืฆื”ื•ื‘'),
('ื”ื›ื ืช ืชืฉืชื™ืช ื’ื’', 'ืงื•ื ืกื˜ืจื•ืงืฆื™ื”, ื‘ื™ืกื•ืก, ื”ื’ื‘ื”ื•ืช โ€” ื‘ืชื™ืื•ื ืขื ืงื‘ืœืŸ ืฉืœื“ (ืœื ื›ืœื•ืœ ื‘ื”ืฆืขืช ืื ื˜ืžืŸ)'),
('ืกื™ืžื•ืŸ ืžื™ืงื•ื ืžืžื™ืจ ื•ืกื•ืœืœื”', 'ืงื™ืจ ื—ื™ืฆื•ื ื™ ืžื•ืฆืœ, ื’ื•ื‘ื” 60+ ืก"ืž, ืžืจื•ื•ื— ืื•ื•ืจื•ืจ 30 ืก"ืž ืžืฆื“ื“ื™ื, 50 ืก"ืž ืžืœืžืขืœื”. ื ื’ื™ืฉ ืœืชื—ื–ื•ืงื”'),
])
add_checklist_table('ืฉืœื‘ ื‘\' โ€” ื”ืชืงื ื” ืžื›ื ื™ืช', [
('ื”ืชืงื ืช ืงื•ื ืกื˜ืจื•ืงืฆื™ื” ืขืœ ื”ื’ื’', 'ื‘ื™ืกื•ืก ืžืกื™ืœื•ืช ืœืคื™ ืชื›ื ื™ืช ื’ื’. ื•ื™ื“ื•ื ื™ืฆื™ื‘ื•ืช ืจื•ื—ื•ืช, ืฉื™ืคื•ืข ื ื™ืงื•ื–, ื•ืื˜ื™ืžืช ื—ื“ื™ืจื•ืช ื’ื’'),
('ื”ืจื›ื‘ืช ืคืื ืœื™ื', '18 ืคืื ืœื™ื x 620W. ื—ืœื•ืงื”: ืกื˜ืจื™ื ื’ 1 (9 ื™ื—\') ื•ืกื˜ืจื™ื ื’ 2 (9 ื™ื—\'). ื—ื™ื‘ื•ืจ ื˜ื•ืจื™ ื‘ื›ืœ ืกื˜ืจื™ื ื’. ื”ืืจืงืช ืžืกื’ืจื•ืช'),
('ื”ืชืงื ืช ืžืžื™ืจ ืขืœ ื”ืงื™ืจ', 'Solis S6-EH3P20K-H โ€” ืชืœื™ื™ื” ืขื ื‘ื•ืจื’ื™ ื”ืจื—ื‘ื” ืžืชืื™ืžื™ื. ื•ื™ื“ื•ื ืžืคืœืก'),
('ื”ืชืงื ืช ืกื•ืœืœื”', 'CNTE 18.8kWh โ€” ืœื™ื“ ื”ืžืžื™ืจ. ื•ื™ื“ื•ื ื™ืฆื™ื‘ื•ืช, ื—ื™ื–ื•ืง ืœืงื™ืจ ืื ื ื“ืจืฉ (ืžืฉืงืœ ~100 ืง"ื’)'),
('ื”ืชืงื ืช ืœื•ื— ืžืคืกืงื™ื', 'ืœื•ื— ื™ื™ืขื•ื“ื™ ืื• ืชื•ืกืคืช ืœืœื•ื— ืงื™ื™ื: ืžืคืกืงื™ื, SPD, ื‘ื•ืจืจ ืžืฆื‘ื™ื, RCD. ืกื™ืžื•ืŸ ื‘ืจื•ืจ ืขืœ ื›ืœ ืžืคืกืง'),
])
add_checklist_table('ืฉืœื‘ ื’\' โ€” ื›ื‘ื™ืœื” ื•ื—ื™ื‘ื•ืจื™ื ื—ืฉืžืœื™ื™ื', [
('ื›ื‘ื™ืœืช DC โ€” ืคืื ืœื™ื ืœืžืžื™ืจ', 'H1Z2Z2-K 6mmยฒ, MC4 connectors. ืกื˜ืจื™ื ื’ 1 โ†’ MPPT1, ืกื˜ืจื™ื ื’ 2 โ†’ MPPT2. ืœื•ื•ื“ื ืงื•ื˜ื‘ื™ื•ืช! + ืœ-+, โ€“ ืœ-โ€“'),
('DC Isolators โ€” PV', 'ื”ืชืงื ืช 2 DC Isolators (1000Vdc/32A) โ€” ืื—ื“ ืœื›ืœ ืกื˜ืจื™ื ื’. ืœื™ื“ ื›ื ื™ืกืช ื”ืžืžื™ืจ ืื• ืœื™ื“ ื”ืคืื ืœื™ื'),
('ื›ื‘ื™ืœืช DC โ€” ืกื•ืœืœื”', 'ื›ื‘ืœ 16mmยฒ ื“ืจืš DC Isolator (800Vdc/63A). ืœื”ืขื‘ื™ืจ ื“ืจืš ื˜ื‘ืขืช ืžื’ื ื˜ื™ืช x 2 ืœื™ืคื•ืคื™ื. ืžื•ืžื ื˜ ื”ื™ื“ื•ืง: 24.5 Nยทm. ื‘ื“ื™ืงืช ืงื•ื˜ื‘ื™ื•ืช ืœืคื ื™ ื—ื™ื‘ื•ืจ!'),
('ื›ื‘ืœ BMS/CAN', 'ื›ื‘ืœ CAN ืžืกื•ื›ืš ืžื”ืกื•ืœืœื” ืœืžืžื™ืจ. ืœื”ืขื‘ื™ืจ ื“ืจืš ื˜ื‘ืขืช ืžื’ื ื˜ื™ืช x 4 ืœื™ืคื•ืคื™ื.'),
('ื›ื‘ื™ืœืช AC โ€” ื™ืฆื™ืืช Grid', 'NYY-J 5G10 (3L+N+PE) ืžื™ืฆื™ืืช Grid ืฉืœ ื”ืžืžื™ืจ โ†’ CT โ†’ SPD AC โ†’ MCB C50 โ†’ ื‘ื•ืจืจ ืžืฆื‘ื™ื โ†’ ื”ืชืคืฆืœื•ืช'),
('ื›ื‘ื™ืœืช AC โ€” Backup', 'NYY-J 5G6 ืžื™ืฆื™ืืช Backup ืฉืœ ื”ืžืžื™ืจ โ†’ MCB C40 4P โ†’ ืœื•ื— ืขื•ืžืกื™ื ื—ื™ื•ื ื™ื™ื'),
('ื—ื™ื‘ื•ืจ ืœืจืฉืช ื”ื™ื™ืฉื•ื‘', 'ืžืขื ืฃ ื”ืจืฉืช ื‘ื‘ื•ืจืจ โ†’ MCB C50 โ†’ ืžื•ื ื” ื™ื™ืฉื•ื‘ โ†’ ืจืฉืช'),
('ื”ืืจืงื”', 'ื›ื‘ืœ 16mmยฒ ื ื—ื•ืฉืช ื™ืจื•ืง-ืฆื”ื•ื‘: ืžืžื™ืจ + ืกื•ืœืœื” + ืงื•ื ืกื˜ืจื•ืงืฆื™ื” + ืžืกื’ืจื•ืช ืคืื ืœื™ื โ†’ ืคืก ื”ืืจืงื” โ†’ ืืœืงื˜ืจื•ื“ื”'),
])
# Phase D - tests
add_heading_rtl('ืฉืœื‘ ื“\' โ€” ื‘ื“ื™ืงื•ืช ืœืคื ื™ ื”ืคืขืœื”', level=2)
tests = [
('ืžื“ื™ื“ืช Voc ืœื›ืœ ืกื˜ืจื™ื ื’', '~396V (ยฑ5%). ื”ืคืจืฉ ื‘ื™ืŸ ืกื˜ืจื™ื ื’ื™ื: ืœื ื™ื•ืชืจ ืž-5%'),
('ืžื“ื™ื“ืช Isc ืœื›ืœ ืกื˜ืจื™ื ื’', '~18A ื‘ืฉืžืฉ ืžืœืื”. ืœื‘ื“ื•ืง ืขื ืžื•ื“ื“ DC rated'),
('ื‘ื“ื™ืงืช ืงื•ื˜ื‘ื™ื•ืช DC', '+ ืœ-+ ื•-โ€“ ืœ-โ€“ ื‘ื›ืœ ื ืงื•ื“ืช ื—ื™ื‘ื•ืจ. ื—ื™ื‘ื•ืจ ื”ืคื•ืš ื”ื•ืจืก ืืช ื”ืžืžื™ืจ!'),
('ื‘ื“ื™ืงืช ื‘ื™ื“ื•ื“ DC', 'ืžื’ืจ: >1Mฮฉ ื‘ื™ืŸ + ืœืื“ืžื”, ื•ื‘ื™ืŸ โ€“ ืœืื“ืžื”'),
('ื‘ื“ื™ืงืช ืจืฆื™ืคื•ืช ื”ืืจืงื”', '<0.5ฮฉ ื‘ื™ืŸ ื›ืœ ืžืกื’ืจืช ืคืื ืœ / ื’ื•ืฃ ืžืžื™ืจ ืœืคืก ื”ืืจืงื”'),
('ื‘ื“ื™ืงืช ืžืชื— ืกื•ืœืœื”', 'ืžืชื— ืชืงื™ืŸ ื‘ื˜ื•ื•ื— 120โ€“800V. SOC ืžื™ื ื™ืžืœื™ ~20% ืœืคื ื™ ื”ืคืขืœื” ืจืืฉื•ื ื”'),
('ื‘ื“ื™ืงืช ืชืงืฉื•ืจืช BMS', 'ื•ื™ื“ื•ื ืฉื”ืžืžื™ืจ ืžื–ื”ื” ืืช ื”ืกื•ืœืœื” ื•ืžืฆื™ื’ SOC, ืžืชื—, ื˜ืžืคืจื˜ื•ืจื”'),
('ื‘ื“ื™ืงืช ืžืคืกืงื™ื ื•-RCD', 'ื”ืคืขืœื” ื•ื ื™ืชื•ืง ื™ื“ื ื™ ืฉืœ ื›ืœ ืžืคืกืง. ื‘ื“ื™ืงืช RCD ืขื ื›ืคืชื•ืจ TEST'),
('ื‘ื“ื™ืงืช AC โ€” ืžืชื— ื‘ื™ืŸ ืคืื–ื•ืช', '~400V ื‘ื™ืŸ ืคืื–ื•ืช, ~230V ื‘ื™ืŸ ืคืื–ื” ืœื ื™ื™ื˜ืจืœ'),
]
table = add_table_rtl(len(tests) + 1, 3)
for i, h in enumerate(['โ˜', 'ื‘ื“ื™ืงื”', 'ืขืจืš ืฆืคื•ื™ / ืงืจื™ื˜ืจื™ื•ืŸ']):
bold_cell(table.rows[0].cells[i], h)
shade_cells(table.rows[0], '0C2340')
for cell in table.rows[0].cells:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_idx, (test, expected) in enumerate(tests):
table.rows[row_idx + 1].cells[0].text = 'โ˜'
set_cell_rtl(table.rows[row_idx + 1].cells[0])
bold_cell(table.rows[row_idx + 1].cells[1], test)
table.rows[row_idx + 1].cells[2].text = expected
set_cell_rtl(table.rows[row_idx + 1].cells[2])
# Phase E - commissioning
add_checklist_table('ืฉืœื‘ ื”\' โ€” ื”ืคืขืœื” ืจืืฉื•ื ื” (Commissioning)', [
('ื”ืคืขืœื” ืœืคื™ ืกื“ืจ', '1. ืกื’ื•ืจ DC Isolator ืฉืœ ืกื•ืœืœื” โ†’ 2. ืกื’ื•ืจ DC Isolators ืฉืœ PV โ†’ 3. ืกื’ื•ืจ ืžืคืกืง AC โ†’ 4. ื”ืคืขืœ ืžืžื™ืจ'),
('ื”ื’ื“ืจื•ืช ืžืžื™ืจ', 'ื“ืจืš Bluetooth + APP: ื”ื’ื“ืจืช ืกื•ื’ ืกื•ืœืœื” (Lithium/CAN), ืžืฆื‘ ืขื‘ื•ื“ื” (Self-use / Feed-in / Zero Export), ืฉืขื•ืช ื˜ืขื™ื ื”/ืคืจื™ืงื”, ืชื“ืจ ืจืฉืช (50Hz), ืžืชื— ืจืฉืช (400V)'),
('ื”ืคืขืœืช AFCI', 'ื‘ื”ื’ื“ืจื•ืช ื”ืžืžื™ืจ โ€” activation required. ื”ื’ื ืช ืงืฉืช ื—ืฉืžืœื™ืช ื‘ืฆื“ DC'),
('ื”ื’ื“ืจืช CT', 'ื›ื™ื•ื•ืŸ CT (ื—ืฅ ืœื›ื™ื•ื•ืŸ ื”ืจืฉืช). ื”ื’ื“ืจืช zero export ืื ื ื“ืจืฉ. ื‘ื“ื™ืงื”: ื›ืฉื”ืžืขืจื›ืช ืžื™ื™ืฆืจืช, CT ืฆืจื™ืš ืœื”ืจืื•ืช ืขืจืš ืฉืœื™ืœื™ (ื™ื™ืฆื•ื)'),
('ื‘ื“ื™ืงืช Backup', 'ื ื™ืชื•ืง ืžืคืกืง ืจืฉืช ื™ื“ื ื™ืช โ†’ ื•ื™ื“ื•ื ืฉืขื•ืžืกื™ื ื—ื™ื•ื ื™ื™ื ืžืžืฉื™ื›ื™ื ืœืขื‘ื•ื“ ืชื•ืš <10ms โ†’ ื—ื™ื‘ื•ืจ ืžื—ื“ืฉ'),
('ื—ื™ื‘ื•ืจ WiFi/Ethernet', 'ื—ื™ื‘ื•ืจ ื”ืžืžื™ืจ ืœืจืฉืช ืœืฆื•ืจืš ื ื™ื˜ื•ืจ ืžืจื—ื•ืง ื“ืจืš ืืคืœื™ืงืฆื™ื™ืช Solis. ื”ื’ื“ืจืช ื—ืฉื‘ื•ืŸ ื‘-SolisCloud'),
('ื ื™ื˜ื•ืจ 24 ืฉืขื•ืช', 'ืžืขืงื‘ ื‘ื™ื•ื ื”ืจืืฉื•ืŸ: ื™ื™ืฆื•ืจ PV, ื˜ืขื™ื ืช ืกื•ืœืœื”, ืฆืจื™ื›ื”, ื™ื™ืฆื•ื/ื™ื™ื‘ื•ื ืžืจืฉืช. ื•ื™ื“ื•ื ืฉืื™ืŸ ืฉื’ื™ืื•ืช'),
])
# Phase F - labeling
add_checklist_table('ืฉืœื‘ ื•\' โ€” ืกื™ืžื•ืŸ ื•ืชื™ืขื•ื“', [
('ืกื™ืžื•ืŸ ืžืคืกืงื™ื', 'ืชื•ื•ื™ืช ื‘ืจื•ืจื” ืขืœ ื›ืœ ืžืคืกืง: "PV String 1", "PV String 2", "ืกื•ืœืœื” DC", "AC ืžืžื™ืจ", "ืจืฉืช", "ืขื•ืžืกื™ื", "Backup", "SPD"'),
('ืกื™ืžื•ืŸ DC Isolators', 'ืชื•ื•ื™ืช ืื“ื•ืžื”: "ื–ื”ื™ืจื•ืช โ€” ืžืชื— DC ื’ื‘ื•ื” ืขื“ 800V" ืขืœ ื›ืœ DC Isolator'),
('ืฉืœื˜ ื›ื™ื‘ื•ื™ ื—ื™ืจื•ื', 'ืฉืœื˜ ืœื™ื“ ื”ืžืžื™ืจ: "ื›ื™ื‘ื•ื™ ื—ื™ืจื•ื โ€” 1. ื ืชืง DC Isolators (PV + ืกื•ืœืœื”) 2. ื ืชืง ืžืคืกืง AC"'),
('ืชื™ืขื•ื“', 'ืœืฉืžื•ืจ ืขื•ืชืง ืฉืœ: ืชื›ื ื™ืช ื—ืฉืžืœื™ืช, ืื™ืฉื•ืจื™ ื‘ื“ื™ืงื”, ืžืกืคืจื™ื ืกื™ื“ื•ืจื™ื™ื (ืžืžื™ืจ + ืกื•ืœืœื” + ืคืื ืœื™ื), ืชืžื•ื ื•ืช ื”ืชืงื ื”'),
('ืžืกื™ืจื” ืœืœืงื•ื—', 'ื”ื“ืจื›ืช ืฉื™ืžื•ืฉ: ืืคืœื™ืงืฆื™ื”, ืžืฆื‘ื™ ืขื‘ื•ื“ื”, ื›ื™ื‘ื•ื™ ื—ื™ืจื•ื, ืชื—ื–ื•ืงื” ืฉื•ื˜ืคืช (ื ื™ืงื•ื™ ืคืื ืœื™ื ื›ืœ 3 ื—ื•ื“ืฉื™ื)'),
])
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• 11. EMERGENCY SHUTDOWN โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_heading_rtl('11. ื ื•ื”ืœ ื›ื™ื‘ื•ื™ ื—ื™ืจื•ื', level=1)
add_para_rtl('ื‘ืžืงืจื” ืฉืœ ืฉืจื™ืคื”, ื”ืฆืคื”, ื ื–ืง ืคื™ื–ื™ ืœืฆื™ื•ื“, ืื• ื›ืœ ืžืฆื‘ ื—ื™ืจื•ื:')
emergency_steps = [
('1', 'ื ืชืง DC โ€” ืกื•ืœืœื”', 'DC Isolator ืฉืœ ื”ืกื•ืœืœื” โ†’ ืžืฆื‘ OFF'),
('2', 'ื ืชืง DC โ€” ืคืื ืœื™ื', 'ืฉื ื™ DC Isolators ืฉืœ PV โ†’ ืžืฆื‘ OFF'),
('3', 'ื ืชืง AC โ€” ืžืžื™ืจ', 'ืžืคืกืง ื™ืฆื™ืืช ืžืžื™ืจ (C50) โ†’ ืžืฆื‘ OFF'),
('4', 'ื ืชืง ืจืฉืช', 'ืžืคืกืง ืจืฉืช (C50) โ†’ ืžืฆื‘ OFF'),
]
table = add_table_rtl(len(emergency_steps) + 1, 3)
for i, h in enumerate(['ืฉืœื‘', 'ืคืขื•ืœื”', 'ืคื™ืจื•ื˜']):
bold_cell(table.rows[0].cells[i], h)
shade_cells(table.rows[0], 'C62828')
for cell in table.rows[0].cells:
for p in cell.paragraphs:
for run in p.runs:
run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
for row_idx, (step, action, detail) in enumerate(emergency_steps):
bold_cell(table.rows[row_idx + 1].cells[0], step)
bold_cell(table.rows[row_idx + 1].cells[1], action)
table.rows[row_idx + 1].cells[2].text = detail
set_cell_rtl(table.rows[row_idx + 1].cells[2])
shade_cells(table.rows[row_idx + 1], 'FFEBEE')
add_para_rtl('')
add_para_rtl('โš  ื–ื”ื™ืจื•ืช: ื’ื ืœืื—ืจ ื ื™ืชื•ืง ื›ืœ ื”ืžืคืกืงื™ื, ื”ืคืื ืœื™ื ืขืฆืžื ืžืžืฉื™ื›ื™ื ืœื™ื™ืฆืจ ืžืชื— ื›ืœ ืขื•ื“ ื™ืฉ ืื•ืจ. ืžืชื— ืžืขื’ืœ ืคืชื•ื—: ~396V ืœืกื˜ืจื™ื ื’. ืื™ืŸ ืœื’ืขืช ื‘ื—ื™ื‘ื•ืจื™ MC4 ืื• ื‘ื›ื‘ืœื™ DC ืœืœื ืฆื™ื•ื“ ืžื’ืŸ ืžืชืื™ื ื•ื‘ื“ื™ืงื” ืขื ืžื•ื“ื“.', bold=True, color=RGBColor(0xC6, 0x28, 0x28))
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• FOOTER โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
add_para_rtl('')
p = add_para_rtl('ืžืกืžืš ื–ื” ื”ื•ื›ืŸ ืœืฆืจื›ื™ ืชื›ื ื•ืŸ ื‘ืœื‘ื“ ื•ืื™ื ื• ืžื”ื•ื•ื” ืชื›ื ื™ืช ื—ืฉืžืœื™ืช ืจืฉืžื™ืช. ื™ืฉ ืœื•ื•ื“ื ืขื ื—ืฉืžืœืื™ ืžื•ืกืžืš ืœืคื ื™ ื‘ื™ืฆื•ืข.', size=10, color=RGBColor(0x99, 0x99, 0x99))
add_para_rtl('ื—ื•ื•ืช ื™ืื™ืจ โ€” ืืœื™ ืกืคืจื | ืžืจืฅ 2026', size=10, color=RGBColor(0x99, 0x99, 0x99))
# โ”€โ”€ Save โ”€โ”€
output_path = os.path.expanduser('~/Documents/GitHub/Baseline/ืชื›ื ื™ืช_ื—ืฉืžืœื™ืช_ื—ื•ื•ืช_ื™ืื™ืจ.docx')
doc.save(output_path)
print(f'Saved to: {output_path}')