-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f22c5f7
commit 2cb57ba
Showing
53 changed files
with
4,820 additions
and
3,142 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ dist | |
packages | ||
.webpack | ||
out | ||
yarn-error.log |
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* @zjouba |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Contributing | ||
|
||
We really appreciate any contributions that help improve Shed Shield. All contributions are welcome, including feature requests, issues, documentation, and discussions. | ||
|
||
## Got a question? | ||
|
||
You can ask questions, see announcements, and discuss Shed Shield related topics on the [Discussion page](https://github.com/ZJouba/ShedShield/discussions). | ||
|
||
## Found a bug? | ||
|
||
If you find any bugs please help us by [submitting an issue](https://github.com/ZJouba/ShedShield/issues/new?labels=bug) to our GitHub Repository. | ||
|
||
## Missing a feature? | ||
|
||
You can request a new feature by [submitting an issue](https://github.com/ZJouba/ShedShield/issues/new?labels=enhancement) to our GitHub Repository. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,90 @@ | ||
## Electron + TypeScript + React | ||
<h1 align='center'> | ||
<br> | ||
<img src='./assets/icon.png' alt='Shed Shield' width=200> | ||
<br> | ||
Shed Shield | ||
<br> | ||
</h1> | ||
|
||
Boilerplate for a project using Electron, React and Typescript. | ||
<h4 align='center'>A handy little utility to shutdown your PC before loadingshedding hits. Built with <a href="https://www.electronjs.org/" target="_blank">Electron</a>.</h4> | ||
|
||
## Installation | ||
<div align='center'> | ||
<a href='https://github.com/zjouba/shedshield/releases'> | ||
|
||
<img src='https://img.shields.io/github/v/release/zjouba/shedshield?color=%23FDD835&label=version&style=for-the-badge'> | ||
|
||
</a> | ||
|
||
Use a package manager of your choice (npm, yarn, etc.) in order to install all dependencies | ||
<a href='https://github.com/zjouba/shedshield/blob/master/LICENSE'> | ||
|
||
<img src='https://img.shields.io/github/license/zjouba/shedshield?style=for-the-badge'> | ||
|
||
</a> | ||
</div> | ||
<br /> | ||
|
||
```bash | ||
yarn | ||
``` | ||
--- | ||
|
||
## Usage | ||
<div align='center'> | ||
|
||
Just run `start` script. | ||
**[SHED SHIELD](#🛡️shed-shield) • | ||
[KEY FEATURES](#🔧-key-features) • | ||
[FIRST TIME SETUP](#⌨️-first-time-setup) • | ||
[DOWNLOAD](#💾-download) • | ||
[CONTRIBUTING](#🦾-contributing) • | ||
[SUPPORT](#🙏support) • | ||
[LICENSE](#📜-license)** | ||
|
||
```bash | ||
yarn start | ||
``` | ||
</div> | ||
|
||
## Packaging | ||
# 🛡️Shed Shield | ||
Shed Shield uses the [EskomSePush](https://documenter.getpostman.com/view/1296288/UzQuNk3E#intro) API along with [Nominatum](https://nominatim.openstreetmap.org/ui/about.html) to look up your zone and adds a cron job to shutdown your PC before loadshedding cuts the power. | ||
|
||
To generate the project package based on the OS you're running on, just run: | ||
# 🔧 Key Features | ||
* Shed Shield uses geolocation to find your closest zone | ||
* Shed Shield can monitor multiple zones | ||
* Shed Shield uses the most immediate loadshedding timeslot to schedule a shutdown | ||
* Shed Shield can be configured to shutdown at specified intervals before loadshedding | ||
|
||
```bash | ||
yarn package | ||
``` | ||
# ⌨️ First time setup | ||
### 1. EskomSePush API | ||
a. Before running Shed Shield, navigate to [EskomSePush API Subscription](https://eskomsepush.gumroad.com/l/api) and subscribe to the free tier | ||
<img src='.github/assets/step1.png' alt='Shed Shield' width=500> | ||
b. Complete your details | ||
<img src='.github/assets/step2.png' alt='Shed Shield' width=500> | ||
c. Use the provided API key when setting up Shed Shield | ||
|
||
## Contributing | ||
### 2. Shed Shield | ||
When running Shed Shield for the first time, you first have to setup your API Key and then your zones. | ||
a. Run Shed Shield | ||
<img src='.github/assets/step3.png' alt='Shed Shield' width=500> | ||
b. Follow the instructions and go to the Settings tab | ||
<img src='.github/assets/step4.png' alt='Shed Shield' width=500> | ||
c. Enter the API Key from [Step 1](#1-eskomsepush-api) into the input field | ||
d. Click the Save Settings button | ||
e. Search for your street address or nearest location using the Address lookup | ||
<img src='.github/assets/step5.png' alt='Shed Shield' width=500> | ||
f. Click SEARCH FOR YOUR ZONE to search for your closest Zone | ||
<b>NB! Don't search for too many zones, this request uses 5 units of your API quota with EskomSePush!</b> | ||
g. Select the zones you want to monitor, the interval and be sure to check Launch at startup to have worry free shutdowns | ||
<img src='.github/assets/step6.png' alt='Shed Shield' width=500> | ||
h. And that's all there is too it | ||
<img src='.github/assets/step7.png' alt='Shed Shield' width=500> | ||
|
||
Pull requests are always welcome 😃. | ||
You can also see at what time the app will shutdown in the system tray | ||
<img src='.github/assets/tray.png' alt='Shed Shield' width=200> | ||
|
||
## License | ||
<h3>Be sure to keep the app running in order to schedule the shutdowns. It will minimize to the system tray</h2> | ||
<br> | ||
|
||
[MIT](https://choosealicense.com/licenses/mit/) | ||
# 💾 Download | ||
You can [download](https://github.com/zjouba/shedshield/releases/tag/latest) the Shed Shield installer for Windows. (macOS & Linux are WIP) | ||
|
||
# 🦾 Contributing | ||
Shed Shield is an open-source project. We appreciate the community's involvement and feedback. Please refer to our [contribution](https://github.com/zjouba/shedshield/blob/master/contributing.md) guide for more information. | ||
|
||
# 🙏Support | ||
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/B0B5NRT22) | ||
|
||
# 📜 License | ||
Shed Shield is free and open-source software licensed under the [GNU General Public License v3.0.](https://github.com/zjouba/shedshield/blob/master/license) |
Empty file.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import Store from 'electron-store' | ||
import ISettings from '../../src/interfaces/ISettings'; | ||
const ESP = 'https://developer.sepush.co.za/business/2.0/' | ||
|
||
const store = new Store() | ||
|
||
const ESPToken = () => { | ||
return { | ||
headers: { | ||
'Token': (store.get('settings') as ISettings)?.apiKey | ||
} | ||
} | ||
}; | ||
|
||
export const espAPI = { | ||
searchArea: (searchQuery: string): Promise<Response> => fetch(`${ESP}areas_search?${searchQuery}`, {method: 'GET', ...ESPToken()}), | ||
|
||
areaInfo: (id: string): Promise<Response> => fetch(`${ESP}area?id=${id}${process.env.NODE_ENV !== 'production' ? '&test=current' : ''}`, {method: 'GET', ...ESPToken()}), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const NOMINATIM = 'https://nominatim.openstreetmap.org/' | ||
|
||
export const geolocateAPI = { | ||
search: (searchQuery: string): Promise<Response> => fetch(`${NOMINATIM}search?format=json&countrycodes=za&q=${searchQuery}`, {method: 'GET'}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,54 @@ | ||
import { contextBridge, ipcRenderer } from 'electron' | ||
import { contextBridge, ipcRenderer } from 'electron'; | ||
import ISettings from '../src/interfaces/ISettings'; | ||
import { Dayjs } from 'dayjs'; | ||
|
||
export const api = { | ||
/** | ||
* Here you can expose functions to the renderer process | ||
* so they can interact with the main (electron) side | ||
* without security problems. | ||
* | ||
* The function below can accessed using `window.Main.sendMessage` | ||
*/ | ||
const api = { | ||
getSettings: async () => { | ||
return await ipcRenderer.invoke('getSettings'); | ||
}, | ||
|
||
saveSettings: async (settings: ISettings) => { | ||
return await ipcRenderer.invoke('saveSettings', settings); | ||
}, | ||
|
||
searchArea: async (searchQuery: string) => { | ||
return await ipcRenderer.invoke('searchArea', searchQuery); | ||
}, | ||
|
||
geolocate: async (searchQuery: string) => { | ||
return await ipcRenderer.invoke('geolocate', searchQuery); | ||
}, | ||
|
||
getAreaInfo: async (id: string) => { | ||
return await ipcRenderer.invoke('getAreaInfo', id); | ||
}, | ||
|
||
sendMessage: (message: string) => { | ||
ipcRenderer.send('message', message) | ||
setCron: async (cron: Date, formatted: string) => { | ||
return await ipcRenderer.invoke('setCron', cron, formatted); | ||
}, | ||
|
||
info: async (...args: any[]) => { | ||
ipcRenderer.send('info', args); | ||
}, | ||
|
||
warn: async (...args: any[]) => { | ||
ipcRenderer.send('warn', args); | ||
}, | ||
|
||
error: async (...args: any[]) => { | ||
ipcRenderer.send('error', args); | ||
}, | ||
|
||
/** | ||
* Provide an easier way to listen to events | ||
*/ | ||
on: (channel: string, callback: Function) => { | ||
ipcRenderer.on(channel, (_, data) => callback(data)) | ||
} | ||
} | ||
|
||
contextBridge.exposeInMainWorld('Main', api) | ||
|
||
const theme = { | ||
set: async (theme: string) => { | ||
ipcRenderer.invoke('setTheme', theme); | ||
} | ||
} | ||
contextBridge.exposeInMainWorld('theme', theme); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { IpcMain, Tray, app, nativeTheme } from 'electron' | ||
import { geolocateAPI } from './api/geolocate.api' | ||
import { espAPI } from './api/esp.api' | ||
import Store from 'electron-store' | ||
import ISettings from '../src/interfaces/ISettings' | ||
import { CronJob } from 'cron' | ||
import { shutdown } from './utils/shutdown' | ||
import logger from './utils/logger' | ||
import { Dayjs } from 'dayjs' | ||
|
||
const store = new Store() | ||
|
||
export const registerHandlers = (ipcMain: IpcMain, tray: Tray | null) => { | ||
let job: CronJob | ||
|
||
ipcMain.handle('getSettings', () => { | ||
const settings: ISettings = store.get('settings') as ISettings || { | ||
espAreas: [], | ||
theme: '', | ||
interval: 0, | ||
runAtStartup: false, | ||
}; | ||
|
||
if (!settings.theme) | ||
settings.theme = nativeTheme.shouldUseDarkColors ? 'dark' : 'light' | ||
return settings | ||
}); | ||
|
||
ipcMain.handle('saveSettings', (event: any, settings: ISettings) => { | ||
store.set('settings', settings); | ||
app.setLoginItemSettings({ | ||
openAtLogin: settings.runAtStartup | ||
}); | ||
}); | ||
|
||
ipcMain.handle('setTheme', (event: any, theme: string) => { | ||
nativeTheme.themeSource = theme as ('system' | 'light' | 'dark'); | ||
}); | ||
|
||
ipcMain.handle('searchArea', async (event: any, searchQuery: string) => { | ||
try { | ||
const response = await espAPI.searchArea(searchQuery); | ||
const results = await response.json(); | ||
return results?.areas; | ||
} catch (error) { | ||
logger.error(error) | ||
return []; | ||
} | ||
}); | ||
|
||
ipcMain.handle('geolocate', async (event: any, searchQuery: string) => { | ||
const response = await geolocateAPI.search(searchQuery) | ||
return await response.json() | ||
}); | ||
|
||
ipcMain.handle('getAreaInfo', async (event: any, id: string) => { | ||
const response = await espAPI.areaInfo(id) | ||
return await response.json() | ||
}); | ||
|
||
ipcMain.handle('setCron', async (event: any, cron: Date, formatted: string) => { | ||
if (job) { | ||
job.stop() | ||
} | ||
try { | ||
job = new CronJob( | ||
cron, | ||
() => { | ||
shutdown(); | ||
}, | ||
null, | ||
true, | ||
); | ||
tray?.setToolTip(`Shutting down at ${formatted}`); | ||
} catch (e) { | ||
logger.error(e); | ||
} | ||
}); | ||
|
||
ipcMain.handle('info', async (event: any, ...args: any[]) => logger.info(args)); | ||
ipcMain.handle('error', async (event: any, ...args: any[]) => logger.error(args)); | ||
ipcMain.handle('warn', async (event: any, ...args: any[]) => logger.warn(args)); | ||
} |
Oops, something went wrong.