decharge-scout 2.5.5 β 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env +18 -0
- package/.env.example +12 -1
- package/README.md +93 -29
- package/index.js +175 -87
- package/package.json +8 -3
- package/src/energy-data.js +264 -8
- package/src/local-alpha.js +325 -0
- package/src/smart-pricing.js +251 -0
- package/src/weather-data.js +117 -0
package/.env
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# EIA API Key (Required - Get from https://www.eia.gov/opendata/register.php)
|
|
2
|
+
EIA_API_KEY=w0FzlyIlSkmb0Rw8H8IpxssShajZkQp9eT2sAZ0V
|
|
3
|
+
|
|
4
|
+
# Solana Configuration
|
|
5
|
+
SOLANA_NETWORK=devnet
|
|
6
|
+
SOLANA_RPC_URL=https://api.devnet.solana.com
|
|
7
|
+
|
|
8
|
+
# Mock Oracle Escrow Address (Replace with your test wallet for demo)
|
|
9
|
+
ORACLE_ESCROW_ADDRESS=YourDevWalletPublicKeyHere
|
|
10
|
+
|
|
11
|
+
# Dashboard API (Optional - for testing dashboard integration)
|
|
12
|
+
DASHBOARD_API_URL=http://localhost:3000/submit
|
|
13
|
+
|
|
14
|
+
# Stake Amount (in SOL)
|
|
15
|
+
STAKE_AMOUNT=0.01
|
|
16
|
+
|
|
17
|
+
# Premium Feature Price (in SOL)
|
|
18
|
+
PREMIUM_PRICE=0.001
|
package/.env.example
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Energy Data API Keys
|
|
2
|
+
# Choose ONE based on your location (FREE options available!):
|
|
3
|
+
#
|
|
4
|
+
# πΊπΈ USA (FREE): EIA API - Get from https://www.eia.gov/opendata/register.php
|
|
2
5
|
EIA_API_KEY=your_eia_api_key_here
|
|
6
|
+
#
|
|
7
|
+
# πͺπΊ Europe (FREE): ENTSO-E - Get from https://transparency.entsoe.eu/
|
|
8
|
+
ENTSOE_API_KEY=your_entsoe_api_key_here
|
|
9
|
+
#
|
|
10
|
+
# π¬π§ UK (NO KEY NEEDED): Carbon Intensity API is completely FREE!
|
|
11
|
+
#
|
|
12
|
+
# π Global (PAID): Electricity Maps - Get from https://www.electricitymaps.com/
|
|
13
|
+
ELECTRICITY_MAPS_API_KEY=your_electricity_maps_api_key_here
|
|
3
14
|
|
|
4
15
|
# Solana Configuration
|
|
5
16
|
SOLANA_NETWORK=devnet
|
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# π Global Energy Scout
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Weather-powered intelligent energy price forecasting with Solana blockchain integration.**
|
|
4
|
+
|
|
5
|
+
This CLI tool uses **real-time weather data** to simulate energy grid pricing globally, helping you find the cheapest EV charging windows. No expensive APIs needed - completely FREE weather-based simulation that works worldwide!
|
|
4
6
|
|
|
5
7
|
## π Quick Install
|
|
6
8
|
|
|
@@ -14,22 +16,47 @@ Then run: `decharge-scout`
|
|
|
14
16
|
|
|
15
17
|
[See more installation options β](ONE_COMMAND_INSTALL.md)
|
|
16
18
|
|
|
17
|
-
## Features
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- **
|
|
21
|
-
-
|
|
22
|
-
- **
|
|
23
|
-
- **
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
19
|
+
## β¨ Features
|
|
20
|
+
|
|
21
|
+
### π€οΈ **Weather-Powered Simulation** (NEW!)
|
|
22
|
+
- **FREE** real-time weather data from Open-Meteo API (no key required!)
|
|
23
|
+
- Simulates energy pricing based on:
|
|
24
|
+
- π‘οΈ **Temperature** (AC/heating demand)
|
|
25
|
+
- π¨ **Wind speed** (renewable energy availability)
|
|
26
|
+
- βοΈ **Solar radiation** (solar energy generation)
|
|
27
|
+
- π **Time-of-day** patterns (peak/off-peak)
|
|
28
|
+
- **50+ regional pricing models** (US, EU, IN, BR, JP, AU, etc.)
|
|
29
|
+
- Intelligent insights explaining **why** certain times are cheaper
|
|
30
|
+
|
|
31
|
+
### π§ **Smart Optimization**
|
|
32
|
+
- Finds the cheapest 1-hour EV charging window in next 24 hours
|
|
33
|
+
- Shows weather conditions at optimal time
|
|
34
|
+
- Calculates potential savings (%)
|
|
35
|
+
- Regional peak/off-peak pattern matching
|
|
36
|
+
|
|
37
|
+
### π **Local Alpha Contribution**
|
|
38
|
+
- Share your local grid knowledge (e.g., "7-9PM peak in Lagos")
|
|
39
|
+
- Earn bonus points for contributing
|
|
40
|
+
- Community-driven peak time database
|
|
41
|
+
|
|
42
|
+
### βοΈ **Blockchain Integration**
|
|
43
|
+
- Submits results to Solana devnet with anti-spam staking
|
|
44
|
+
- Points system for successful submissions
|
|
45
|
+
- x402 micropayments for premium features (optional)
|
|
46
|
+
|
|
47
|
+
### πΊοΈ **Global Coverage**
|
|
48
|
+
- Works **anywhere in the world**
|
|
49
|
+
- Auto-detects location via IP
|
|
50
|
+
- Custom location override supported
|
|
51
|
+
- Dashboard-ready structured output
|
|
26
52
|
|
|
27
53
|
## Prerequisites
|
|
28
54
|
|
|
29
55
|
- Node.js v20 or higher
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
56
|
+
- **NO API KEYS REQUIRED!** π
|
|
57
|
+
- Uses FREE Open-Meteo weather API (no registration needed)
|
|
58
|
+
- Works globally without any paid subscriptions
|
|
59
|
+
- At least 0.02 SOL in your devnet wallet for staking + fees (auto-airdropped in setup)
|
|
33
60
|
|
|
34
61
|
## Installation
|
|
35
62
|
|
|
@@ -233,19 +260,47 @@ decharge-scout/
|
|
|
233
260
|
|
|
234
261
|
## API Data Sources
|
|
235
262
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
- Endpoint
|
|
243
|
-
- Provides
|
|
244
|
-
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
-
|
|
263
|
+
The CLI uses **smart routing** to automatically choose the best FREE API based on your location!
|
|
264
|
+
|
|
265
|
+
### π FREE APIs (Recommended!)
|
|
266
|
+
|
|
267
|
+
#### πΊπΈ EIA API (US-only, FREE)
|
|
268
|
+
- **Coverage**: United States only (ERCOT, CAISO, NYISO, PJM, MISO, ISNE)
|
|
269
|
+
- **Endpoint**: `https://api.eia.gov/v2/electricity/rto/region-data/data/`
|
|
270
|
+
- **Provides**: Real-time demand and pricing for US grid regions
|
|
271
|
+
- **Get Key**: FREE at https://www.eia.gov/opendata/register.php
|
|
272
|
+
- **Auto-used for**: Texas, California, New York, etc.
|
|
273
|
+
|
|
274
|
+
#### πͺπΊ ENTSO-E (Europe, FREE)
|
|
275
|
+
- **Coverage**: All European countries
|
|
276
|
+
- **Endpoint**: `https://web-api.tp.entsoe.eu/api`
|
|
277
|
+
- **Provides**: Day-ahead electricity prices and demand forecasts
|
|
278
|
+
- **Get Key**: FREE at https://transparency.entsoe.eu/
|
|
279
|
+
- **Auto-used for**: Germany, France, Spain, Italy, Poland, Netherlands, Belgium, Austria
|
|
280
|
+
- **Registration**: Free account required, instant approval
|
|
281
|
+
|
|
282
|
+
#### π¬π§ UK Carbon Intensity (UK, FREE - No key needed!)
|
|
283
|
+
- **Coverage**: United Kingdom only
|
|
284
|
+
- **Endpoint**: `https://api.carbonintensity.org.uk`
|
|
285
|
+
- **Provides**: Real-time carbon intensity and price forecasts
|
|
286
|
+
- **Get Key**: No key needed! Completely open API
|
|
287
|
+
- **Auto-used for**: UK locations (works out of the box!)
|
|
288
|
+
|
|
289
|
+
### π° PAID API (Global fallback)
|
|
290
|
+
|
|
291
|
+
#### π Electricity Maps (GLOBAL, PAID)
|
|
292
|
+
- **Coverage**: Global (India, EU, UK, Australia, US, and more)
|
|
293
|
+
- **Endpoint**: `https://api.electricitymaps.com/v3/carbon-intensity/forecast`
|
|
294
|
+
- **Provides**: Carbon intensity forecasts and grid data for 200+ zones
|
|
295
|
+
- **Get Key**: Paid API at https://www.electricitymaps.com/
|
|
296
|
+
- **Auto-used for**: India, Australia, and regions not covered by free APIs
|
|
297
|
+
- **Pricing**: Expensive - use only if free options don't cover your region
|
|
298
|
+
|
|
299
|
+
### π Mock Data (FREE - Always available!)
|
|
300
|
+
- **Coverage**: Worldwide
|
|
301
|
+
- **Generated**: Locally using realistic pricing patterns
|
|
302
|
+
- **Auto-used**: When no API keys are configured or all APIs fail
|
|
303
|
+
- **Perfect for**: Testing, demos, and development
|
|
249
304
|
|
|
250
305
|
## Points System
|
|
251
306
|
|
|
@@ -264,8 +319,17 @@ decharge-scout/
|
|
|
264
319
|
|
|
265
320
|
## Troubleshooting
|
|
266
321
|
|
|
267
|
-
### "EIA_API_KEY not
|
|
268
|
-
|
|
322
|
+
### "EIA_API_KEY not configured" or "No energy data API keys configured"
|
|
323
|
+
Choose an API based on your location:
|
|
324
|
+
- **US users**: Get FREE EIA API key from https://www.eia.gov/opendata/register.php
|
|
325
|
+
- **International users**: Get Electricity Maps API key from https://www.electricitymaps.com/
|
|
326
|
+
- **Testing**: Press Enter to skip and use mock data
|
|
327
|
+
|
|
328
|
+
Add your key to `.env`:
|
|
329
|
+
```
|
|
330
|
+
EIA_API_KEY=your_key_here # For US
|
|
331
|
+
ELECTRICITY_MAPS_API_KEY=your_key_here # For global
|
|
332
|
+
```
|
|
269
333
|
|
|
270
334
|
### "Insufficient balance"
|
|
271
335
|
Fund your devnet wallet:
|
package/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* Global Energy Scout - Intelligent Energy Price Forecasting CLI
|
|
5
|
+
* Powered by real-time weather data and smart simulation
|
|
5
6
|
*
|
|
6
7
|
* Main entry point for the CLI application that scouts energy grid data,
|
|
7
8
|
* performs optimizations, and submits results to Solana blockchain.
|
|
@@ -26,18 +27,20 @@ import path from 'path';
|
|
|
26
27
|
import { fileURLToPath } from 'url';
|
|
27
28
|
import { dirname } from 'path';
|
|
28
29
|
|
|
29
|
-
// Load environment variables
|
|
30
|
-
dotenv.config();
|
|
30
|
+
// Load environment variables from current working directory (not package dir)
|
|
31
|
+
dotenv.config({ path: path.join(process.cwd(), '.env') });
|
|
31
32
|
|
|
32
33
|
// Import modules
|
|
33
34
|
import { startWalletServer, openWalletConnection, waitForWalletConnection, getConnectedWallet } from './src/wallet-server.js';
|
|
34
35
|
import { setConnectedWallet, getBalance, checkBalance, mockStake, refundStake } from './src/browser-wallet.js';
|
|
35
|
-
import {
|
|
36
|
+
import { getWeatherForLocation } from './src/weather-data.js';
|
|
37
|
+
import { generateSmartPricing, getPricingInsights, getRegionalPricing } from './src/smart-pricing.js';
|
|
36
38
|
import { findCheapestWindow, calculateSavings } from './src/optimizer.js';
|
|
37
39
|
import { submitToOracle } from './src/oracle.js';
|
|
38
40
|
import { initializePoints, awardPoints, getPoints, savePoints } from './src/points.js';
|
|
39
41
|
import { getLocation } from './src/geolocation.js';
|
|
40
42
|
import { purchasePremiumData } from './src/x402.js';
|
|
43
|
+
import { hasBeenAskedForAlpha, markAskedForAlpha, parseAlphaContribution, saveAlphaContribution, calculateAlphaBonus, getAlphaInsights, verifyContribution, getInformationSources } from './src/local-alpha.js';
|
|
41
44
|
|
|
42
45
|
const __filename = fileURLToPath(import.meta.url);
|
|
43
46
|
const __dirname = dirname(__filename);
|
|
@@ -71,52 +74,52 @@ function generateAgentName() {
|
|
|
71
74
|
* Auto-configure .env if needed
|
|
72
75
|
*/
|
|
73
76
|
async function ensureEnvironment() {
|
|
74
|
-
|
|
77
|
+
// Use current working directory for .env (so npx works correctly)
|
|
78
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
75
79
|
|
|
76
80
|
// Create .env from example if missing
|
|
77
81
|
if (!existsSync(envPath)) {
|
|
82
|
+
// Look for .env.example in package directory
|
|
78
83
|
const examplePath = path.join(__dirname, '.env.example');
|
|
79
84
|
if (existsSync(examplePath)) {
|
|
80
85
|
console.log(chalk.yellow('β οΈ .env file not found, creating from template...'));
|
|
81
86
|
const example = readFileSync(examplePath, 'utf-8');
|
|
82
87
|
writeFileSync(envPath, example);
|
|
83
|
-
console.log(chalk.green(
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Check for EIA API key
|
|
88
|
-
if (!process.env.EIA_API_KEY || process.env.EIA_API_KEY === 'your_eia_api_key_here') {
|
|
89
|
-
console.log(chalk.yellow('\nβ οΈ EIA_API_KEY not configured'));
|
|
90
|
-
console.log(chalk.blue('\nπ How to get a FREE EIA API key:'));
|
|
91
|
-
console.log(chalk.gray(' 1. Visit: https://www.eia.gov/opendata/register.php'));
|
|
92
|
-
console.log(chalk.gray(' 2. Fill out the registration form'));
|
|
93
|
-
console.log(chalk.gray(' 3. Check your email and verify your email address'));
|
|
94
|
-
console.log(chalk.gray(' 4. Your API key will be sent to your email'));
|
|
95
|
-
console.log(chalk.gray(' 5. Copy the API key and paste it below\n'));
|
|
96
|
-
|
|
97
|
-
const answer = await question('Enter your EIA API key (or press Enter to skip): ');
|
|
98
|
-
|
|
99
|
-
if (answer.trim()) {
|
|
100
|
-
// Update .env file
|
|
101
|
-
let envContent = readFileSync(envPath, 'utf-8');
|
|
102
|
-
envContent = envContent.replace(/EIA_API_KEY=.*/g, `EIA_API_KEY=${answer.trim()}`);
|
|
103
|
-
writeFileSync(envPath, envContent);
|
|
104
|
-
|
|
105
|
-
// Update process.env
|
|
106
|
-
process.env.EIA_API_KEY = answer.trim();
|
|
107
|
-
|
|
108
|
-
console.log(chalk.green('β API key saved to .env'));
|
|
88
|
+
console.log(chalk.green(`β .env file created at ${envPath}`));
|
|
109
89
|
} else {
|
|
110
|
-
|
|
90
|
+
// Create a basic .env file if no example exists
|
|
91
|
+
const basicEnv = `# Energy Data API Keys
|
|
92
|
+
# Choose ONE based on your location:
|
|
93
|
+
# - EIA (FREE, US-only): Get from https://www.eia.gov/opendata/register.php
|
|
94
|
+
# - Electricity Maps (GLOBAL, paid): Get from https://www.electricitymaps.com/
|
|
95
|
+
EIA_API_KEY=your_eia_api_key_here
|
|
96
|
+
ELECTRICITY_MAPS_API_KEY=your_electricity_maps_api_key_here
|
|
97
|
+
|
|
98
|
+
# Solana Configuration
|
|
99
|
+
SOLANA_NETWORK=devnet
|
|
100
|
+
SOLANA_RPC_URL=https://api.devnet.solana.com
|
|
101
|
+
|
|
102
|
+
# Stake Amount (in SOL)
|
|
103
|
+
STAKE_AMOUNT=0.01
|
|
104
|
+
`;
|
|
105
|
+
writeFileSync(envPath, basicEnv);
|
|
106
|
+
console.log(chalk.green(`β .env file created at ${envPath}`));
|
|
111
107
|
}
|
|
112
108
|
}
|
|
109
|
+
|
|
110
|
+
// Info: No API keys needed for weather-based simulation!
|
|
111
|
+
console.log(chalk.green('\nβ
Using FREE weather-based simulation (no API keys required!)'));
|
|
112
|
+
console.log(chalk.gray(' β’ Real-time weather data from Open-Meteo'));
|
|
113
|
+
console.log(chalk.gray(' β’ Smart pricing based on temperature, wind, solar radiation'));
|
|
114
|
+
console.log(chalk.gray(' β’ Regional patterns for accurate predictions\n'));
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
/**
|
|
116
118
|
* Main CLI function
|
|
117
119
|
*/
|
|
118
120
|
async function main(options) {
|
|
119
|
-
console.log(chalk.cyan.bold('\n
|
|
121
|
+
console.log(chalk.cyan.bold('\nπ Global Energy Scout - Intelligent Price Forecasting\n'));
|
|
122
|
+
console.log(chalk.gray(' Powered by real-time weather data & smart simulation'));
|
|
120
123
|
|
|
121
124
|
try {
|
|
122
125
|
// Auto-configure environment
|
|
@@ -169,49 +172,19 @@ async function main(options) {
|
|
|
169
172
|
const detectedLocation = await getLocation();
|
|
170
173
|
locationSpinner.succeed(chalk.green(`π Detected Location: ${detectedLocation}`));
|
|
171
174
|
|
|
172
|
-
// Ask user to confirm or override (
|
|
175
|
+
// Ask user to confirm or override (no timeout - wait for input)
|
|
173
176
|
console.log(chalk.blue('\nYou can use this location or enter a custom one.'));
|
|
174
|
-
console.log(chalk.gray('(Press Enter to use detected location, or type custom location)'));
|
|
175
|
-
console.log(chalk.gray('You have 30 seconds to respond...'));
|
|
177
|
+
console.log(chalk.gray('(Press Enter to use detected location, or type a custom location like "Dallas,TX,USA")'));
|
|
176
178
|
|
|
177
179
|
try {
|
|
178
|
-
|
|
179
|
-
let hasResolved = false;
|
|
180
|
-
|
|
181
|
-
// Create a promise that auto-resolves after 30 seconds
|
|
182
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
183
|
-
timeoutId = setTimeout(() => {
|
|
184
|
-
if (!hasResolved) {
|
|
185
|
-
hasResolved = true;
|
|
186
|
-
console.log(chalk.yellow('\nβ±οΈ Timeout - using detected location...'));
|
|
187
|
-
resolve('__TIMEOUT__');
|
|
188
|
-
}
|
|
189
|
-
}, 30000);
|
|
190
|
-
});
|
|
180
|
+
const customLocation = await question('Enter location (or press Enter for auto-detected): ');
|
|
191
181
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return answer;
|
|
197
|
-
}
|
|
198
|
-
return '__TIMEOUT__'; // If timeout already occurred, ignore this answer
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const customLocation = await Promise.race([questionPromise, timeoutPromise]);
|
|
202
|
-
|
|
203
|
-
// If timeout occurred, use detected location
|
|
204
|
-
if (customLocation === '__TIMEOUT__') {
|
|
205
|
-
location = detectedLocation;
|
|
206
|
-
console.log(chalk.green(`β Using detected location: ${location}`));
|
|
182
|
+
// Use custom location if provided, otherwise use detected
|
|
183
|
+
location = customLocation.trim() || detectedLocation;
|
|
184
|
+
if (customLocation.trim()) {
|
|
185
|
+
console.log(chalk.green(`β Using custom location: ${location}`));
|
|
207
186
|
} else {
|
|
208
|
-
|
|
209
|
-
location = customLocation.trim() || detectedLocation;
|
|
210
|
-
if (customLocation.trim()) {
|
|
211
|
-
console.log(chalk.green(`β Using custom location: ${location}`));
|
|
212
|
-
} else {
|
|
213
|
-
console.log(chalk.green(`β Using detected location: ${location}`));
|
|
214
|
-
}
|
|
187
|
+
console.log(chalk.green(`β Using detected location: ${location}`));
|
|
215
188
|
}
|
|
216
189
|
} catch (error) {
|
|
217
190
|
console.log(chalk.yellow(`\nβ οΈ Prompt error, using detected location: ${detectedLocation}`));
|
|
@@ -280,24 +253,31 @@ async function runQueryCycle(wallet, agentName, location, options) {
|
|
|
280
253
|
console.log(chalk.cyan.bold(`π Run #${totalRuns} - ${new Date().toLocaleString()}`));
|
|
281
254
|
console.log(chalk.cyan(`ββββββββββββββββββββββββββββββββββββββββ\n`));
|
|
282
255
|
|
|
283
|
-
// Fetch
|
|
284
|
-
const
|
|
285
|
-
let energyData;
|
|
256
|
+
// Fetch weather data and generate smart pricing simulation
|
|
257
|
+
const weatherSpinner = ora('Fetching real-time weather forecast...').start();
|
|
258
|
+
let weatherData, energyData, countryCode;
|
|
286
259
|
|
|
287
260
|
try {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
261
|
+
// Get real weather forecast from Open-Meteo (FREE!)
|
|
262
|
+
weatherData = await getWeatherForLocation(location);
|
|
263
|
+
countryCode = weatherData.location.country || 'DEFAULT';
|
|
264
|
+
weatherSpinner.succeed(chalk.green(`β Fetched ${weatherData.forecast.length}h weather forecast (FREE!)`));
|
|
265
|
+
|
|
266
|
+
// Generate intelligent pricing based on weather + regional patterns
|
|
267
|
+
const pricingSpinner = ora('Simulating energy grid pricing...').start();
|
|
268
|
+
energyData = generateSmartPricing(weatherData, countryCode);
|
|
269
|
+
pricingSpinner.succeed(chalk.green(`β Generated ${energyData.length} hours of smart pricing data`));
|
|
270
|
+
|
|
271
|
+
// Show pricing insights
|
|
272
|
+
const insights = getPricingInsights(energyData, countryCode);
|
|
273
|
+
console.log(chalk.blue(`\nπ‘ Smart Simulation Insights:`));
|
|
274
|
+
console.log(chalk.gray(` Region: ${insights.region}`));
|
|
275
|
+
console.log(chalk.gray(` Price range: $${insights.minPrice}-$${insights.maxPrice}/kWh (${insights.priceRange}% variation)`));
|
|
276
|
+
console.log(chalk.gray(` Savings potential: ${insights.savingsPotential}% by timing your charge`));
|
|
293
277
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
} catch (fallbackError) {
|
|
298
|
-
dataSpinner.fail(chalk.red('All data sources failed'));
|
|
299
|
-
throw new Error('Unable to fetch energy data from any source');
|
|
300
|
-
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
weatherSpinner.fail(chalk.red('Failed to fetch weather data'));
|
|
280
|
+
throw new Error(`Unable to generate pricing simulation: ${error.message}`);
|
|
301
281
|
}
|
|
302
282
|
|
|
303
283
|
// Run optimization
|
|
@@ -306,12 +286,31 @@ async function runQueryCycle(wallet, agentName, location, options) {
|
|
|
306
286
|
const savings = calculateSavings(energyData, cheapestWindow);
|
|
307
287
|
optSpinner.succeed(chalk.green('Optimization complete'));
|
|
308
288
|
|
|
309
|
-
// Display results
|
|
289
|
+
// Display results with intelligent insights
|
|
310
290
|
console.log(chalk.green.bold('\n⨠Optimization Results:'));
|
|
311
291
|
console.log(chalk.white(` Cheapest charge window: ${cheapestWindow.timeWindow}`));
|
|
312
292
|
console.log(chalk.white(` Price: $${cheapestWindow.price.toFixed(4)}/kWh`));
|
|
313
293
|
console.log(chalk.white(` Savings: ${savings.toFixed(1)}%`));
|
|
314
294
|
|
|
295
|
+
// Show why this time is cheap (weather-based reasons)
|
|
296
|
+
const cheapestHourData = energyData.find(d => d.hour === cheapestWindow.hour);
|
|
297
|
+
if (cheapestHourData && cheapestHourData.reasons) {
|
|
298
|
+
console.log(chalk.blue('\nπ§ Why this time is optimal:'));
|
|
299
|
+
cheapestHourData.reasons.forEach(reason => {
|
|
300
|
+
console.log(chalk.gray(` β’ ${reason}`));
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Show weather conditions
|
|
304
|
+
if (cheapestHourData.weather) {
|
|
305
|
+
console.log(chalk.blue('\nπ€οΈ Weather conditions at optimal time:'));
|
|
306
|
+
console.log(chalk.gray(` Temperature: ${cheapestHourData.weather.temperature.toFixed(1)}Β°C`));
|
|
307
|
+
console.log(chalk.gray(` Wind: ${cheapestHourData.weather.windSpeed.toFixed(1)} m/s`));
|
|
308
|
+
if (cheapestHourData.hour >= 6 && cheapestHourData.hour <= 18) {
|
|
309
|
+
console.log(chalk.gray(` Solar: ${cheapestHourData.weather.solarRadiation.toFixed(0)} W/mΒ²`));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
315
314
|
// Prepare submission data
|
|
316
315
|
const submissionData = {
|
|
317
316
|
agent_name: agentName,
|
|
@@ -379,6 +378,95 @@ async function runQueryCycle(wallet, agentName, location, options) {
|
|
|
379
378
|
console.log(chalk.magenta(`\nβ Earned ${totalPointsEarned} points! (${basePoints} base${bonusPoints > 0 ? ` + ${bonusPoints} bonus` : ''})`));
|
|
380
379
|
console.log(chalk.magenta(`β Total Points: ${currentPoints}`));
|
|
381
380
|
|
|
381
|
+
// Local Alpha Contribution (ask once after first run)
|
|
382
|
+
if (totalRuns === 1 && !hasBeenAskedForAlpha()) {
|
|
383
|
+
console.log(chalk.cyan('\nπ‘ Local Alpha Contribution - Help Improve Global Energy Data!'));
|
|
384
|
+
console.log(chalk.gray(' Share your local electricity peak time knowledge for bonus points.\n'));
|
|
385
|
+
|
|
386
|
+
// Show where to find this information
|
|
387
|
+
console.log(chalk.blue('π Where to find peak time information:'));
|
|
388
|
+
const sources = getInformationSources(location);
|
|
389
|
+
|
|
390
|
+
// General sources
|
|
391
|
+
sources.general.forEach(source => {
|
|
392
|
+
console.log(chalk.gray(` ${source}`));
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Region-specific sources
|
|
396
|
+
const regionKeys = Object.keys(sources.byRegion);
|
|
397
|
+
if (regionKeys.length > 0) {
|
|
398
|
+
console.log(chalk.blue('\nπ For your region:'));
|
|
399
|
+
regionKeys.forEach(region => {
|
|
400
|
+
sources.byRegion[region].forEach(source => {
|
|
401
|
+
console.log(chalk.gray(` ${source}`));
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
console.log(chalk.blue('\n㪠Examples of good contributions:'));
|
|
407
|
+
console.log(chalk.gray(' β’ "7-9PM peak in Lagos" (evening peak)'));
|
|
408
|
+
console.log(chalk.gray(' β’ "1-5AM cheap in Berlin" (off-peak)'));
|
|
409
|
+
console.log(chalk.gray(' β’ "5-8PM peak in Mumbai" (dinner time surge)'));
|
|
410
|
+
console.log(chalk.gray(' β’ "2-6AM cheap in Texas" (wind energy overnight)\n'));
|
|
411
|
+
|
|
412
|
+
const alphaInput = await question(chalk.blue('Share local peak times (or press Enter to skip): '));
|
|
413
|
+
|
|
414
|
+
if (alphaInput.trim()) {
|
|
415
|
+
const parsed = parseAlphaContribution(alphaInput, location);
|
|
416
|
+
if (parsed) {
|
|
417
|
+
// Verify contribution against current pricing data
|
|
418
|
+
const verification = verifyContribution(parsed, energyData);
|
|
419
|
+
|
|
420
|
+
// Save contribution with verification status
|
|
421
|
+
const contribution = saveAlphaContribution(parsed, agentName, location, verification);
|
|
422
|
+
|
|
423
|
+
// Calculate bonus (higher for verified contributions)
|
|
424
|
+
const alphaBonus = calculateAlphaBonus(parsed, verification);
|
|
425
|
+
|
|
426
|
+
awardPoints(wallet, alphaBonus);
|
|
427
|
+
|
|
428
|
+
console.log(chalk.green(`\nβ
Thanks for contributing! Earned ${alphaBonus} bonus points!`));
|
|
429
|
+
console.log(chalk.gray(` Contribution: ${parsed.type} hours ${parsed.startHour}-${parsed.endHour} in ${parsed.location}`));
|
|
430
|
+
|
|
431
|
+
// Show verification results
|
|
432
|
+
if (verification.verified) {
|
|
433
|
+
console.log(chalk.green(` π― Verified! Confidence: ${(verification.confidence * 100).toFixed(0)}%`));
|
|
434
|
+
verification.reasons.forEach(reason => {
|
|
435
|
+
console.log(chalk.gray(` ${reason}`));
|
|
436
|
+
});
|
|
437
|
+
console.log(chalk.green(` +${alphaBonus - 10} extra points for verified contribution!`));
|
|
438
|
+
} else {
|
|
439
|
+
console.log(chalk.yellow(` β οΈ Low confidence: ${(verification.confidence * 100).toFixed(0)}%`));
|
|
440
|
+
verification.reasons.forEach(reason => {
|
|
441
|
+
console.log(chalk.gray(` ${reason}`));
|
|
442
|
+
});
|
|
443
|
+
console.log(chalk.gray(` Tip: Contributions that match actual price patterns earn more points!`));
|
|
444
|
+
}
|
|
445
|
+
} else {
|
|
446
|
+
console.log(chalk.yellow('β οΈ Could not parse contribution.'));
|
|
447
|
+
console.log(chalk.gray(' Accepted formats:'));
|
|
448
|
+
console.log(chalk.gray(' β’ "7-9PM peak in Lagos"'));
|
|
449
|
+
console.log(chalk.gray(' β’ "1-5AM cheap in Berlin"'));
|
|
450
|
+
console.log(chalk.gray(' β’ "19-21 peak Mumbai" (24-hour format also works)'));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
markAskedForAlpha();
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Show alpha insights if available
|
|
458
|
+
if (totalRuns === 1) {
|
|
459
|
+
const alphaInsights = getAlphaInsights(location);
|
|
460
|
+
if (alphaInsights && alphaInsights.contributions > 0) {
|
|
461
|
+
console.log(chalk.cyan(`\nπ Community Knowledge for ${location}:`));
|
|
462
|
+
console.log(chalk.gray(` ${alphaInsights.contributions} local contribution(s)`));
|
|
463
|
+
if (alphaInsights.commonPeakHours.length > 0) {
|
|
464
|
+
const topPeaks = alphaInsights.commonPeakHours.map(p => `${p.hour}:00`).join(', ');
|
|
465
|
+
console.log(chalk.gray(` Most reported peak hours: ${topPeaks}`));
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
382
470
|
// Premium upgrade option
|
|
383
471
|
if (options.premium && totalRuns % 3 === 0) {
|
|
384
472
|
console.log(chalk.yellow('\nπ Premium Feature Available!'));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "decharge-scout",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Global Energy Scout - Weather-powered intelligent energy price forecasting with Solana integration",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -20,7 +20,12 @@
|
|
|
20
20
|
"blockchain",
|
|
21
21
|
"ev-charging",
|
|
22
22
|
"energy-optimization",
|
|
23
|
-
"
|
|
23
|
+
"weather",
|
|
24
|
+
"simulation",
|
|
25
|
+
"global",
|
|
26
|
+
"renewable-energy",
|
|
27
|
+
"smart-grid",
|
|
28
|
+
"price-forecasting",
|
|
24
29
|
"web3"
|
|
25
30
|
],
|
|
26
31
|
"author": "",
|