Solar Array and home energy dashboard.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

134 lines
3.2 KiB

  1. import arrow
  2. import random
  3. import pprint
  4. import json
  5. from datetime import datetime, timedelta
  6. rand = random.Random('a seed')
  7. tz = 'US/Pacific'
  8. startdate = arrow.Arrow(2019, 11, 1, tzinfo=tz)
  9. enddate = arrow.Arrow(2019, 12, 10, tzinfo=tz)
  10. meanwhprod = 20000
  11. sigwhprod = 2000
  12. def drange(s, e, interval):
  13. cmpfun = lambda s, e, ts, te: te < e
  14. if e < s:
  15. interval = -interval
  16. cmpfun = lambda s, e, ts, te: te > e
  17. ts = s.clone()
  18. te = ts + interval
  19. #print('dr:', repr((s, e, ts, te, cmpfun(s, e, ts, te), interval)))
  20. while cmpfun(s, e, ts, te):
  21. yield ts + (te - ts)
  22. ts, te = te, te + interval
  23. # idea:
  24. # first hour linear ramp up (25% in first half, 75% in second half)
  25. # middle 5 hours near constant generation
  26. # first/tailing linear is equiv of an hour total, so total power / 6
  27. # approx 7 hours time
  28. def makestartend(t):
  29. s = t.replace(hour=9).shift(minutes=rand.gauss(30, 10))
  30. e = t.replace(hour=16).shift(minutes=rand.gauss(30, 10))
  31. return (s, e)
  32. def normdist(small, big, amount, minsize):
  33. '''Distribute most twoards the big side, total distribute amount
  34. over the entire range, [small, big].
  35. '''
  36. ret = []
  37. timediff = abs(big - small)
  38. if timediff < minsize:
  39. scaledamount = amount * (timedelta(hours=1) / timediff)
  40. midpnt = small + (big - small) / 2
  41. #print('ndf:', repr((small, big, midpnt, amount, scaledamount)))
  42. return [ (midpnt, scaledamount) ]
  43. #print('nd:', repr((small, big, amount)))
  44. dist = big - small
  45. halfpoint = small + (dist / 9 * 5)
  46. ret.extend(normdist(small, halfpoint, amount / 2, minsize))
  47. ret.extend(normdist(halfpoint, big, amount / 2, minsize))
  48. #print('ndr:')
  49. #pprint.pprint(ret)
  50. return ret
  51. def linramp(start, end, wtarget, minsize):
  52. mid = start + (end - start) / 2
  53. timediff = abs(end - start)
  54. ret = []
  55. ndates = abs((end - start) / minsize)
  56. #print('lr', ndates)
  57. for x, i in enumerate(drange(start, end, minsize)):
  58. #print(repr((x, i)))
  59. yield (i, x / ndates * wtarget)
  60. def distribute(s, e, prod, minsize):
  61. onehour = timedelta(hours=1)
  62. totaltime = e - s
  63. mid = s + totaltime / 2
  64. startrampend = s + onehour
  65. endrampstart = e - onehour
  66. # prod == wh
  67. wtarget = prod / ((totaltime + onehour).seconds / 60 / 60)
  68. ret = []
  69. #print('d:', repr((s, e)))
  70. ret.extend(linramp(s, startrampend, wtarget, minsize))
  71. for i in drange(startrampend, endrampstart, minsize):
  72. ret.append((i, wtarget))
  73. ret.extend(linramp(e, endrampstart, wtarget, minsize))
  74. ret.sort()
  75. #pprint.pprint(ret)
  76. return ret
  77. #print('start')
  78. points = []
  79. index = []
  80. def serializearrowasmili(obj):
  81. if not isinstance(obj, arrow.Arrow):
  82. raise TypeError
  83. return int(obj.float_timestamp*1000)
  84. for i in arrow.Arrow.range('day', startdate, enddate):
  85. whprod = rand.gauss(meanwhprod, sigwhprod)
  86. s, e = makestartend(i)
  87. noon = i.replace(hour=12)
  88. index.append((noon, whprod))
  89. #print(repr(i), whprod)
  90. dist = distribute(s, e, whprod, timedelta(seconds=20))
  91. # print timestamps as miliseconds
  92. if False:
  93. dist = ((int(a.float_timestamp*1000), b) for a, b in dist)
  94. # print space delimited time, else json
  95. if False:
  96. print('\n'.join('%s %s' % (a, b) for a, b in dist))
  97. else:
  98. #print(json.dumps(tuple(dist), indent=2))
  99. points.extend(dist)
  100. print('fakedata =', json.dumps(dict(production=points, index=index), default=serializearrowasmili))