Fetch local weather from Dark Sky API. https://wthr.ml/
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.

131 lines
4.7 KiB

  1. const log = console.log
  2. const fs = require('fs')
  3. const {table, getBorderCharacters} = require('table')
  4. // const argv = require('yargs').argv
  5. const TABLE_CONFIG = {
  6. // columns: {
  7. // 0: { alignment: 'center' },
  8. // 1: { alignment: 'center' },
  9. // 2: { alignment: 'center' },
  10. // },
  11. border: getBorderCharacters(`ramac`)
  12. }
  13. const HIDE_PRECIP_LESS_THAN = 10
  14. // const CREDIT_MSG = "Powered by Dark Sky: https://darksky.net/poweredby/"
  15. // const CREDIT_MSG = "https://darksky.net/poweredby • https://smol.gq/wthr-src\n"
  16. const CREDIT_MSG = "darksky.net/poweredby • smol.gq/wthr-src\n\n"
  17. // https://medium.com/@osiolabs/read-write-json-files-with-node-js-92d03cc82824
  18. const jsonReader = (filePath, cb) => {
  19. fs.readFile(filePath, (err, fileData) => {
  20. if (err) {
  21. log(err)
  22. return cb && cb(err)
  23. }
  24. try {
  25. const object = JSON.parse(fileData)
  26. // log(filePath, object['latitude'])
  27. return cb && cb(null, object)
  28. } catch(err) {
  29. log(err)
  30. return cb && cb(err)
  31. }
  32. })
  33. }
  34. const round5 = x => { return Math.ceil(x / 5) * 5 }
  35. const updateTempHigh = (temp, index, tempHigh) => {
  36. // +1 to offset header
  37. return (temp > tempHigh[0]) ? [temp, index + 1] : tempHigh
  38. }
  39. const updateTempLow = (temp, index, tempLow) => {
  40. return (temp < tempLow[0]) ? [temp, index + 1] : tempLow
  41. }
  42. const getWeatherTable = (jsonFile, loc, orientation) => {
  43. return new Promise((resolve, reject) => {
  44. jsonReader(jsonFile, (err, weatherInfo) => {
  45. if (err) {
  46. reject(err)
  47. }
  48. let output = loc + '\n'
  49. // value, index
  50. let tempHigh = [-100, -1]
  51. let tempLow = [100, -1]
  52. weatherInfo['hourly']['data'][0] = weatherInfo['currently']
  53. if (orientation == 'v') {
  54. const infoList = [['H', '°C', 'R','%P']]
  55. for (let i = 0; i < 12; i++) {
  56. const hourInfo = weatherInfo['hourly']['data'][i]
  57. const date = new Date(hourInfo['time'] * 1000)
  58. const temp = Math.floor(hourInfo['apparentTemperature'])
  59. tempHigh = updateTempHigh(temp, i, tempHigh)
  60. tempLow = updateTempLow(temp, i, tempHigh)
  61. const precipProbability = round5(hourInfo['precipProbability'] * 100)
  62. const precipText = ((precipProbability < HIDE_PRECIP_LESS_THAN)
  63. ? '' : precipProbability)
  64. infoList.push([
  65. date.getHours(),
  66. temp,
  67. ((hourInfo['summary'].includes('Rain')) ? 'Y' : ''),
  68. precipText,
  69. ])
  70. }
  71. infoList[tempHigh[1]][1] = `${infoList[tempHigh[1]][1]}+`
  72. infoList[tempLow[1]][1] = `${infoList[tempLow[1]][1]}-`
  73. output += table(infoList, TABLE_CONFIG)
  74. } else {
  75. // horizontal
  76. const hoursList = ['H']
  77. const tempsList = ['°C']
  78. const rainList = ['R']
  79. const precipList = ['%P']
  80. for (let i = 0; i < 16; i += 2) {
  81. const hourInfo = weatherInfo['hourly']['data'][i]
  82. const date = new Date(hourInfo['time'] * 1000)
  83. const temp = Math.floor(hourInfo['apparentTemperature'])
  84. tempHigh = updateTempHigh(temp, i/2, tempHigh)
  85. tempLow = updateTempLow(temp, i/2, tempHigh)
  86. hoursList.push(date.getHours())
  87. tempsList.push(temp)
  88. rainList.push((hourInfo['summary'].includes('Rain')) ? 'Y' : '')
  89. const precipProbability = round5(hourInfo['precipProbability'] * 100)
  90. precipList.push((precipProbability < HIDE_PRECIP_LESS_THAN)
  91. ? '' : precipProbability)
  92. }
  93. tempsList[tempHigh[1]] = `${tempsList[tempHigh[1]]}+`
  94. tempsList[tempLow[1]] = `${tempsList[tempLow[1]]}-`
  95. output += table([hoursList, tempsList, rainList, precipList],
  96. TABLE_CONFIG)
  97. }
  98. resolve(output)
  99. })
  100. })
  101. }
  102. const formatTimeUnit = unit => { return ((unit < 10) ? '0' : '') + unit }
  103. const getTablePromises = [
  104. getWeatherTable('./markham.json', 'Markham', 'h'),
  105. getWeatherTable('./markham.json', 'Markham', 'v'),
  106. getWeatherTable('./toronto.json', 'Toronto', 'h'),
  107. getWeatherTable('./toronto.json', 'Toronto', 'v'),
  108. ]
  109. Promise.all(getTablePromises).then(tables => {
  110. const mText = tables[0]
  111. const mvText = tables[1]
  112. const tText = tables[2]
  113. const tvText = tables[3]
  114. const writeErrorHandler = error => { if (error) { throw error } }
  115. fs.writeFile('mt.txt', CREDIT_MSG + mText + '\n' + tText, writeErrorHandler)
  116. fs.writeFile('mtv.txt', CREDIT_MSG + mvText + '\n' + tvText, writeErrorHandler)
  117. fs.writeFile('m.txt', CREDIT_MSG + mText, writeErrorHandler)
  118. fs.writeFile('mv.txt', CREDIT_MSG + mvText, writeErrorHandler)
  119. fs.writeFile('t.txt', CREDIT_MSG + tText, writeErrorHandler)
  120. fs.writeFile('tv.txt', CREDIT_MSG + tvText, writeErrorHandler)
  121. })