1#!/usr/bin/env python 2 3""" 4This script reads in fan definition and zone definition YAML 5files and generates a set of structures for use by the fan control code. 6""" 7 8import os 9import sys 10import yaml 11from argparse import ArgumentParser 12from mako.template import Template 13 14tmpl = '''\ 15<%! 16def indent(str, depth): 17 return ''.join(4*' '*depth+line for line in str.splitlines(True)) 18%>\ 19<%def name="genHandler(sig)" buffered="True"> 20%if ('type' in sig['sparams']) and \ 21 (sig['sparams']['type'] is not None): 22${sig['signal']}<${sig['sparams']['type']}>( 23%else: 24${sig['signal']}( 25%endif 26%for spk in sig['sparams']['params']: 27${sig['sparams'][spk]}, 28%endfor 29%if ('type' in sig['hparams']) and \ 30 (sig['hparams']['type'] is not None): 31handler::${sig['handler']}<${sig['hparams']['type']}>( 32%else: 33handler::${sig['handler']}( 34%endif 35%for i, hpk in enumerate(sig['hparams']['params']): 36 %if (i+1) != len(sig['hparams']['params']): 37 ${sig['hparams'][hpk]}, 38 %else: 39 ${sig['hparams'][hpk]} 40 %endif 41%endfor 42)) 43</%def>\ 44<%def name="genSSE(event)" buffered="True"> 45Group{ 46%for group in event['groups']: 47%for member in group['members']: 48{ 49 "${member['object']}", 50 {"${member['interface']}", 51 "${member['property']}"} 52}, 53%endfor 54%endfor 55}, 56std::vector<Action>{ 57%for a in event['action']: 58%if len(a['parameters']) != 0: 59make_action(action::${a['name']}( 60%else: 61make_action(action::${a['name']} 62%endif 63%for i, p in enumerate(a['parameters']): 64%if (i+1) != len(a['parameters']): 65 ${p}, 66%else: 67 ${p}) 68%endif 69%endfor 70), 71%endfor 72}, 73Timer{ 74 ${event['timer']['interval']}, 75 ${event['timer']['type']} 76}, 77std::vector<Signal>{ 78%for s in event['signals']: 79 Signal{ 80 match::${s['match']}( 81 %for i, mp in enumerate(s['mparams']): 82 %if (i+1) != len(s['mparams']): 83 "${mp}", 84 %else: 85 "${mp}" 86 %endif 87 %endfor 88 ), 89 make_handler(\ 90 ${indent(genHandler(sig=s), 3)}\ 91 ) 92 }, 93%endfor 94} 95</%def>\ 96/* This is a generated file. */ 97#include "manager.hpp" 98#include "functor.hpp" 99#include "actions.hpp" 100#include "handlers.hpp" 101#include "preconditions.hpp" 102#include "matches.hpp" 103 104using namespace phosphor::fan::control; 105 106const unsigned int Manager::_powerOnDelay{${mgr_data['power_on_delay']}}; 107 108const std::vector<ZoneGroup> Manager::_zoneLayouts 109{ 110%for zone_group in zones: 111 ZoneGroup{ 112 std::vector<Condition>{ 113 %for condition in zone_group['conditions']: 114 Condition{ 115 "${condition['type']}", 116 std::vector<ConditionProperty>{ 117 %for property in condition['properties']: 118 ConditionProperty{ 119 "${property['property']}", 120 "${property['interface']}", 121 "${property['path']}", 122 static_cast<${property['type']}>(${property['value']}), 123 }, 124 %endfor 125 }, 126 }, 127 %endfor 128 }, 129 std::vector<ZoneDefinition>{ 130 %for zone in zone_group['zones']: 131 ZoneDefinition{ 132 ${zone['num']}, 133 ${zone['full_speed']}, 134 ${zone['default_floor']}, 135 ${zone['increase_delay']}, 136 ${zone['decrease_interval']}, 137 std::vector<FanDefinition>{ 138 %for fan in zone['fans']: 139 FanDefinition{ 140 "${fan['name']}", 141 std::vector<std::string>{ 142 %for sensor in fan['sensors']: 143 "${sensor}", 144 %endfor 145 }, 146 "${fan['target_interface']}" 147 }, 148 %endfor 149 }, 150 std::vector<SetSpeedEvent>{ 151 %for event in zone['events']: 152 %if ('pc' in event) and \ 153 (event['pc'] is not None): 154 SetSpeedEvent{ 155 Group{ 156 %for group in event['pc']['pcgrps']: 157 %for member in group['members']: 158 { 159 "${member['object']}", 160 {"${member['interface']}", 161 "${member['property']}"} 162 }, 163 %endfor 164 %endfor 165 }, 166 std::vector<Action>{ 167 %for i, a in enumerate(event['pc']['pcact']): 168 %if len(a['params']) != 0: 169 make_action( 170 precondition::${a['name']}( 171 %else: 172 make_action( 173 precondition::${a['name']} 174 %endif 175 %for p in a['params']: 176 ${p['type']}${p['open']} 177 %for j, v in enumerate(p['values']): 178 %if (j+1) != len(p['values']): 179 ${v['value']}, 180 %else: 181 ${v['value']} 182 %endif 183 %endfor 184 ${p['close']}, 185 %endfor 186 %if (i+1) != len(event['pc']['pcact']): 187 %if len(a['params']) != 0: 188 )), 189 %else: 190 ), 191 %endif 192 %endif 193 %endfor 194 std::vector<SetSpeedEvent>{ 195 %for pcevt in event['pc']['pcevts']: 196 SetSpeedEvent{\ 197 ${indent(genSSE(event=pcevt), 6)}\ 198 }, 199 %endfor 200 %else: 201 SetSpeedEvent{\ 202 ${indent(genSSE(event=event), 6)} 203 %endif 204 %if ('pc' in event) and (event['pc'] is not None): 205 } 206 %if len(event['pc']['pcact'][-1]['params']) != 0: 207 )), 208 %else: 209 ), 210 %endif 211 }, 212 Timer{ 213 ${event['pc']['pctime']['interval']}, 214 ${event['pc']['pctime']['type']} 215 }, 216 std::vector<Signal>{ 217 %for s in event['pc']['pcsigs']: 218 Signal{ 219 match::${s['match']}( 220 %for i, mp in enumerate(s['mparams']): 221 %if (i+1) != len(s['mparams']): 222 "${mp}", 223 %else: 224 "${mp}" 225 %endif 226 %endfor 227 ), 228 make_handler(\ 229 ${indent(genHandler(sig=s), 9)}\ 230 ) 231 }, 232 %endfor 233 } 234 %endif 235 }, 236 %endfor 237 } 238 }, 239 %endfor 240 } 241 }, 242%endfor 243}; 244''' 245 246 247def convertToMap(listOfDict): 248 """ 249 Converts a list of dictionary entries to a std::map initialization list. 250 """ 251 listOfDict = listOfDict.replace('\'', '\"') 252 listOfDict = listOfDict.replace('[', '{') 253 listOfDict = listOfDict.replace(']', '}') 254 listOfDict = listOfDict.replace(':', ',') 255 return listOfDict 256 257 258def getGroups(zNum, zCond, edata, events): 259 """ 260 Extract and construct the groups for the given event. 261 """ 262 groups = [] 263 for eGroups in edata['groups']: 264 if ('zone_conditions' in eGroups) and \ 265 (eGroups['zone_conditions'] is not None): 266 # Zone conditions are optional in the events yaml but skip 267 # if this event's condition is not in this zone's conditions 268 if all('name' in z and z['name'] is not None and 269 not any(c['name'] == z['name'] for c in zCond) 270 for z in eGroups['zone_conditions']): 271 continue 272 273 # Zone numbers are optional in the events yaml but skip if this 274 # zone's zone number is not in the event's zone numbers 275 if all('zones' in z and z['zones'] is not None and 276 zNum not in z['zones'] 277 for z in eGroups['zone_conditions']): 278 continue 279 280 eGroup = next(g for g in events['groups'] 281 if g['name'] == eGroups['name']) 282 283 group = {} 284 members = [] 285 group['name'] = eGroup['name'] 286 for m in eGroup['members']: 287 member = {} 288 member['path'] = eGroup['type'] 289 member['object'] = (eGroup['type'] + m) 290 member['interface'] = eGroups['interface'] 291 member['property'] = eGroups['property']['name'] 292 member['type'] = eGroups['property']['type'] 293 # Add expected group member's property value if given 294 if ('value' in eGroups['property']) and \ 295 (eGroups['property']['value'] is not None): 296 if isinstance(eGroups['property']['value'], str) or \ 297 "string" in str(member['type']).lower(): 298 member['value'] = ( 299 "\"" + eGroups['property']['value'] + "\"") 300 else: 301 member['value'] = eGroups['property']['value'] 302 members.append(member) 303 group['members'] = members 304 groups.append(group) 305 return groups 306 307 308def getActions(edata, actions, events): 309 """ 310 Extracts and constructs the make_action function call for 311 all the actions within the given event. 312 """ 313 action = [] 314 for eActions in actions['actions']: 315 actions = {} 316 eAction = next(a for a in events['actions'] 317 if a['name'] == eActions['name']) 318 actions['name'] = eAction['name'] 319 params = [] 320 if ('parameters' in eAction) and \ 321 (eAction['parameters'] is not None): 322 for p in eAction['parameters']: 323 param = "static_cast<" 324 if type(eActions[p]) is not dict: 325 if p == 'actions': 326 param = "std::vector<Action>{" 327 pActs = getActions(edata, eActions, events) 328 for a in pActs: 329 if (len(a['parameters']) != 0): 330 param += ( 331 "make_action(action::" + 332 a['name'] + 333 "(\n") 334 for i, ap in enumerate(a['parameters']): 335 if (i+1) != len(a['parameters']): 336 param += (ap + ",") 337 else: 338 param += (ap + ")") 339 else: 340 param += ("make_action(action::" + a['name']) 341 param += ")," 342 param += "}" 343 elif p == 'property': 344 if isinstance(eActions[p], str) or \ 345 "string" in str(eActions[p]['type']).lower(): 346 param += ( 347 str(eActions[p]['type']).lower() + 348 ">(\"" + str(eActions[p]) + "\")") 349 else: 350 param += ( 351 str(eActions[p]['type']).lower() + 352 ">(" + str(eActions[p]['value']).lower() + ")") 353 else: 354 # Default type to 'size_t' when not given 355 param += ("size_t>(" + str(eActions[p]).lower() + ")") 356 else: 357 if p == 'timer': 358 param = ( 359 "Timer{static_cast<std::chrono::seconds>(" + 360 str(eActions[p]['delay']) + "), " + 361 "util::Timer::TimerType::" + 362 str(eActions[p]['type']) + "}") 363 else: 364 param += (str(eActions[p]['type']).lower() + ">(") 365 if p != 'map': 366 if isinstance(eActions[p]['value'], str) or \ 367 "string" in str(eActions[p]['type']).lower(): 368 param += \ 369 "\"" + str(eActions[p]['value']) + "\")" 370 else: 371 param += \ 372 str(eActions[p]['value']).lower() + ")" 373 else: 374 param += ( 375 str(eActions[p]['type']).lower() + 376 convertToMap(str(eActions[p]['value'])) + ")") 377 params.append(param) 378 actions['parameters'] = params 379 action.append(actions) 380 return action 381 382 383def getEvent(zone_num, zone_conditions, e, events_data): 384 """ 385 Parses the sections of an event and populates the properties 386 that construct an event within the generated source. 387 """ 388 event = {} 389 390 # Add set speed event groups 391 grps = getGroups(zone_num, zone_conditions, e, events_data) 392 if not grps: 393 return 394 event['groups'] = grps 395 396 # Add optional set speed actions and function parameters 397 event['action'] = [] 398 if ('actions' in e) and \ 399 (e['actions'] is not None): 400 event['action'] = getActions(e, e, events_data) 401 402 # Add signal handlers 403 signals = [] 404 for group in event['groups']: 405 for member in group['members']: 406 for eMatches in e['matches']: 407 signal = {} 408 eMatch = next(m for m in events_data['matches'] 409 if m['name'] == eMatches['name']) 410 signal['match'] = eMatch['name'] 411 params = [] 412 if ('parameters' in eMatch) and \ 413 (eMatch['parameters'] is not None): 414 for p in eMatch['parameters']: 415 params.append(member[str(p)]) 416 signal['mparams'] = params 417 if ('parameters' in eMatch['signal']) and \ 418 (eMatch['signal']['parameters'] is not None): 419 eSignal = eMatch['signal'] 420 else: 421 eSignal = next(s for s in events_data['signals'] 422 if s['name'] == eMatch['signal']) 423 signal['signal'] = eSignal['name'] 424 sparams = {} 425 if ('parameters' in eSignal) and \ 426 (eSignal['parameters'] is not None): 427 splist = [] 428 for p in eSignal['parameters']: 429 sp = str(p) 430 if (sp != 'type'): 431 splist.append(sp) 432 if (sp != 'group'): 433 sparams[sp] = "\"" + member[sp] + "\"" 434 else: 435 sparams[sp] = "Group{\n" 436 for m in group['members']: 437 sparams[sp] += ( 438 "{\n" + 439 "\"" + str(m['object']) + "\",\n" + 440 "{\"" + str(m['interface']) + "\"," + 441 "\"" + str(m['property']) + "\"}\n" + 442 "},\n") 443 sparams[sp] += "}" 444 else: 445 sparams[sp] = member[sp] 446 sparams['params'] = splist 447 signal['sparams'] = sparams 448 # Add signal handler 449 eHandler = next(h for h in events_data['handlers'] 450 if h['name'] == eSignal['handler']) 451 signal['handler'] = eHandler['name'] 452 hparams = {} 453 if ('parameters' in eHandler) and \ 454 (eHandler['parameters'] is not None): 455 hplist = [] 456 for p in eHandler['parameters']: 457 hp = str(p) 458 if (hp != 'type'): 459 hplist.append(hp) 460 if (hp != 'group'): 461 hparams[hp] = "\"" + member[hp] + "\"" 462 else: 463 hparams[hp] = "Group{\n" 464 for m in group['members']: 465 hparams[hp] += ( 466 "{\n" + 467 "\"" + str(m['object']) + "\",\n" + 468 "{\"" + str(m['interface']) + "\"," + 469 "\"" + str(m['property']) + "\"}\n" + 470 "},\n") 471 hparams[hp] += "}" 472 else: 473 hparams[hp] = member[hp] 474 hparams['params'] = hplist 475 signal['hparams'] = hparams 476 signals.append(signal) 477 event['signals'] = signals 478 479 # Add optional action call timer 480 timer = {} 481 interval = "static_cast<std::chrono::seconds>" 482 if ('timer' in e) and \ 483 (e['timer'] is not None): 484 timer['interval'] = (interval + 485 "(" + 486 str(e['timer']['interval']) + 487 ")") 488 else: 489 timer['interval'] = (interval + 490 "(" + str(0) + ")") 491 timer['type'] = "util::Timer::TimerType::repeating" 492 event['timer'] = timer 493 494 return event 495 496 497def addPrecondition(zNum, zCond, event, events_data): 498 """ 499 Parses the precondition section of an event and populates the necessary 500 structures to generate a precondition for a set speed event. 501 """ 502 precond = {} 503 # Add set speed event precondition group 504 grps = getGroups(zNum, zCond, event['precondition'], events_data) 505 if not grps: 506 return 507 precond['pcgrps'] = grps 508 509 # Add set speed event precondition actions 510 pc = [] 511 pcs = {} 512 pcs['name'] = event['precondition']['name'] 513 epc = next(p for p in events_data['preconditions'] 514 if p['name'] == event['precondition']['name']) 515 params = [] 516 for p in epc['parameters']: 517 param = {} 518 if p == 'groups': 519 param['type'] = "std::vector<PrecondGroup>" 520 param['open'] = "{" 521 param['close'] = "}" 522 values = [] 523 for group in precond['pcgrps']: 524 for pcgrp in group['members']: 525 value = {} 526 value['value'] = ( 527 "PrecondGroup{\"" + 528 str(pcgrp['object']) + "\",\"" + 529 str(pcgrp['interface']) + "\",\"" + 530 str(pcgrp['property']) + "\"," + 531 "static_cast<" + 532 str(pcgrp['type']).lower() + ">") 533 if isinstance(pcgrp['value'], str) or \ 534 "string" in str(pcgrp['type']).lower(): 535 value['value'] += ("(" + str(pcgrp['value']) + ")}") 536 else: 537 value['value'] += \ 538 ("(" + str(pcgrp['value']).lower() + ")}") 539 values.append(value) 540 param['values'] = values 541 params.append(param) 542 pcs['params'] = params 543 pc.append(pcs) 544 precond['pcact'] = pc 545 546 pcevents = [] 547 for pce in event['precondition']['events']: 548 pcevent = getEvent(zNum, zCond, pce, events_data) 549 if not pcevent: 550 continue 551 pcevents.append(pcevent) 552 precond['pcevts'] = pcevents 553 554 # Add precondition signal handlers 555 signals = [] 556 for group in precond['pcgrps']: 557 for member in group['members']: 558 for eMatches in event['precondition']['matches']: 559 signal = {} 560 eMatch = next(m for m in events_data['matches'] 561 if m['name'] == eMatches['name']) 562 signal['match'] = eMatch['name'] 563 params = [] 564 if ('parameters' in eMatch) and \ 565 (eMatch['parameters'] is not None): 566 for p in eMatch['parameters']: 567 params.append(member[str(p)]) 568 signal['mparams'] = params 569 if ('parameters' in eMatch['signal']) and \ 570 (eMatch['signal']['parameters'] is not None): 571 eSignal = eMatch['signal'] 572 else: 573 eSignal = next(s for s in events_data['signals'] 574 if s['name'] == eMatch['signal']) 575 signal['signal'] = eSignal['name'] 576 sparams = {} 577 if ('parameters' in eSignal) and \ 578 (eSignal['parameters'] is not None): 579 splist = [] 580 for p in eSignal['parameters']: 581 sp = str(p) 582 if (sp != 'type'): 583 splist.append(sp) 584 if (sp != 'group'): 585 sparams[sp] = "\"" + member[sp] + "\"" 586 else: 587 sparams[sp] = "Group{\n" 588 for m in group: 589 sparams[sp] += ( 590 "{\n" + 591 "\"" + str(m['object']) + "\",\n" + 592 "{\"" + str(m['interface']) + "\"," + 593 "\"" + str(m['property']) + "\"}\n" + 594 "},\n") 595 sparams[sp] += "}" 596 else: 597 sparams[sp] = member[sp] 598 sparams['params'] = splist 599 signal['sparams'] = sparams 600 # Add signal handler 601 eHandler = next(h for h in events_data['handlers'] 602 if h['name'] == eSignal['handler']) 603 signal['handler'] = eHandler['name'] 604 hparams = {} 605 if ('parameters' in eHandler) and \ 606 (eHandler['parameters'] is not None): 607 hplist = [] 608 for p in eHandler['parameters']: 609 hp = str(p) 610 if (hp != 'type'): 611 hplist.append(hp) 612 if (hp != 'group'): 613 hparams[hp] = "\"" + member[hp] + "\"" 614 else: 615 hparams[hp] = "Group{\n" 616 for m in group: 617 hparams[hp] += ( 618 "{\n" + 619 "\"" + str(m['object']) + "\",\n" + 620 "{\"" + str(m['interface']) + "\"," + 621 "\"" + str(m['property']) + "\"}\n" + 622 "},\n") 623 hparams[hp] += "}" 624 else: 625 hparams[hp] = member[hp] 626 hparams['params'] = hplist 627 signal['hparams'] = hparams 628 signals.append(signal) 629 precond['pcsigs'] = signals 630 631 # Add optional action call timer 632 timer = {} 633 interval = "static_cast<std::chrono::seconds>" 634 if ('timer' in event['precondition']) and \ 635 (event['precondition']['timer'] is not None): 636 timer['interval'] = (interval + 637 "(" + 638 str(event['precondition']['timer']['interval']) + 639 ")") 640 else: 641 timer['interval'] = (interval + 642 "(" + str(0) + ")") 643 timer['type'] = "util::Timer::TimerType::repeating" 644 precond['pctime'] = timer 645 646 return precond 647 648 649def getEventsInZone(zone_num, zone_conditions, events_data): 650 """ 651 Constructs the event entries defined for each zone using the events yaml 652 provided. 653 """ 654 events = [] 655 656 if 'events' in events_data: 657 for e in events_data['events']: 658 event = {} 659 # Add precondition if given 660 if ('precondition' in e) and \ 661 (e['precondition'] is not None): 662 event['pc'] = addPrecondition(zone_num, 663 zone_conditions, 664 e, 665 events_data) 666 else: 667 event = getEvent(zone_num, zone_conditions, e, events_data) 668 if not event: 669 continue 670 events.append(event) 671 672 return events 673 674 675def getFansInZone(zone_num, profiles, fan_data): 676 """ 677 Parses the fan definition YAML files to find the fans 678 that match both the zone passed in and one of the 679 cooling profiles. 680 """ 681 682 fans = [] 683 684 for f in fan_data['fans']: 685 686 if zone_num != f['cooling_zone']: 687 continue 688 689 # 'cooling_profile' is optional (use 'all' instead) 690 if f.get('cooling_profile') is None: 691 profile = "all" 692 else: 693 profile = f['cooling_profile'] 694 695 if profile not in profiles: 696 continue 697 698 fan = {} 699 fan['name'] = f['inventory'] 700 fan['sensors'] = f['sensors'] 701 fan['target_interface'] = f.get( 702 'target_interface', 703 'xyz.openbmc_project.Control.FanSpeed') 704 fans.append(fan) 705 706 return fans 707 708 709def getConditionInZoneConditions(zone_condition, zone_conditions_data): 710 """ 711 Parses the zone conditions definition YAML files to find the condition 712 that match both the zone condition passed in. 713 """ 714 715 condition = {} 716 717 for c in zone_conditions_data['conditions']: 718 719 if zone_condition != c['name']: 720 continue 721 condition['type'] = c['type'] 722 properties = [] 723 for p in c['properties']: 724 property = {} 725 property['property'] = p['property'] 726 property['interface'] = p['interface'] 727 property['path'] = p['path'] 728 property['type'] = p['type'].lower() 729 property['value'] = str(p['value']).lower() 730 properties.append(property) 731 condition['properties'] = properties 732 733 return condition 734 735 736def buildZoneData(zone_data, fan_data, events_data, zone_conditions_data): 737 """ 738 Combines the zone definition YAML and fan 739 definition YAML to create a data structure defining 740 the fan cooling zones. 741 """ 742 743 zone_groups = [] 744 745 for group in zone_data: 746 conditions = [] 747 # zone conditions are optional 748 if 'zone_conditions' in group and group['zone_conditions'] is not None: 749 for c in group['zone_conditions']: 750 751 if not zone_conditions_data: 752 sys.exit("No zone_conditions YAML file but " + 753 "zone_conditions used in zone YAML") 754 755 condition = getConditionInZoneConditions(c['name'], 756 zone_conditions_data) 757 758 if not condition: 759 sys.exit("Missing zone condition " + c['name']) 760 761 conditions.append(condition) 762 763 zone_group = {} 764 zone_group['conditions'] = conditions 765 766 zones = [] 767 for z in group['zones']: 768 zone = {} 769 770 # 'zone' is required 771 if ('zone' not in z) or (z['zone'] is None): 772 sys.exit("Missing fan zone number in " + zone_yaml) 773 774 zone['num'] = z['zone'] 775 776 zone['full_speed'] = z['full_speed'] 777 778 zone['default_floor'] = z['default_floor'] 779 780 # 'increase_delay' is optional (use 0 by default) 781 key = 'increase_delay' 782 zone[key] = z.setdefault(key, 0) 783 784 # 'decrease_interval' is optional (use 0 by default) 785 key = 'decrease_interval' 786 zone[key] = z.setdefault(key, 0) 787 788 # 'cooling_profiles' is optional (use 'all' instead) 789 if ('cooling_profiles' not in z) or \ 790 (z['cooling_profiles'] is None): 791 profiles = ["all"] 792 else: 793 profiles = z['cooling_profiles'] 794 795 fans = getFansInZone(z['zone'], profiles, fan_data) 796 events = getEventsInZone(z['zone'], group['zone_conditions'], 797 events_data) 798 799 if len(fans) == 0: 800 sys.exit("Didn't find any fans in zone " + str(zone['num'])) 801 802 zone['fans'] = fans 803 zone['events'] = events 804 zones.append(zone) 805 806 zone_group['zones'] = zones 807 zone_groups.append(zone_group) 808 809 return zone_groups 810 811 812if __name__ == '__main__': 813 parser = ArgumentParser( 814 description="Phosphor fan zone definition parser") 815 816 parser.add_argument('-z', '--zone_yaml', dest='zone_yaml', 817 default="example/zones.yaml", 818 help='fan zone definitional yaml') 819 parser.add_argument('-f', '--fan_yaml', dest='fan_yaml', 820 default="example/fans.yaml", 821 help='fan definitional yaml') 822 parser.add_argument('-e', '--events_yaml', dest='events_yaml', 823 help='events to set speeds yaml') 824 parser.add_argument('-c', '--zone_conditions_yaml', 825 dest='zone_conditions_yaml', 826 help='conditions to determine zone yaml') 827 parser.add_argument('-o', '--output_dir', dest='output_dir', 828 default=".", 829 help='output directory') 830 args = parser.parse_args() 831 832 if not args.zone_yaml or not args.fan_yaml: 833 parser.print_usage() 834 sys.exit(-1) 835 836 with open(args.zone_yaml, 'r') as zone_input: 837 zone_data = yaml.safe_load(zone_input) or {} 838 839 with open(args.fan_yaml, 'r') as fan_input: 840 fan_data = yaml.safe_load(fan_input) or {} 841 842 events_data = {} 843 if args.events_yaml: 844 with open(args.events_yaml, 'r') as events_input: 845 events_data = yaml.safe_load(events_input) or {} 846 847 zone_conditions_data = {} 848 if args.zone_conditions_yaml: 849 with open(args.zone_conditions_yaml, 'r') as zone_conditions_input: 850 zone_conditions_data = yaml.safe_load(zone_conditions_input) or {} 851 852 zone_config = buildZoneData(zone_data.get('zone_configuration', {}), 853 fan_data, events_data, zone_conditions_data) 854 855 manager_config = zone_data.get('manager_configuration', {}) 856 857 if manager_config.get('power_on_delay') is None: 858 manager_config['power_on_delay'] = 0 859 860 output_file = os.path.join(args.output_dir, "fan_zone_defs.cpp") 861 with open(output_file, 'w') as output: 862 output.write(Template(tmpl).render(zones=zone_config, 863 mgr_data=manager_config)) 864