decharge-scout 2.5.6 β 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 +159 -84
- 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.
|
|
@@ -32,12 +33,14 @@ dotenv.config({ path: path.join(process.cwd(), '.env') });
|
|
|
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);
|
|
@@ -85,51 +88,38 @@ async function ensureEnvironment() {
|
|
|
85
88
|
console.log(chalk.green(`β .env file created at ${envPath}`));
|
|
86
89
|
} else {
|
|
87
90
|
// Create a basic .env file if no example exists
|
|
88
|
-
const basicEnv = `#
|
|
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/
|
|
89
95
|
EIA_API_KEY=your_eia_api_key_here
|
|
96
|
+
ELECTRICITY_MAPS_API_KEY=your_electricity_maps_api_key_here
|
|
90
97
|
|
|
91
98
|
# Solana Configuration
|
|
92
99
|
SOLANA_NETWORK=devnet
|
|
93
100
|
SOLANA_RPC_URL=https://api.devnet.solana.com
|
|
101
|
+
|
|
102
|
+
# Stake Amount (in SOL)
|
|
103
|
+
STAKE_AMOUNT=0.01
|
|
94
104
|
`;
|
|
95
105
|
writeFileSync(envPath, basicEnv);
|
|
96
106
|
console.log(chalk.green(`β .env file created at ${envPath}`));
|
|
97
107
|
}
|
|
98
108
|
}
|
|
99
109
|
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
console.log(chalk.gray(' 2. Fill out the registration form'));
|
|
106
|
-
console.log(chalk.gray(' 3. Check your email and verify your email address'));
|
|
107
|
-
console.log(chalk.gray(' 4. Your API key will be sent to your email'));
|
|
108
|
-
console.log(chalk.gray(' 5. Copy the API key and paste it below\n'));
|
|
109
|
-
|
|
110
|
-
const answer = await question('Enter your EIA API key (or press Enter to skip): ');
|
|
111
|
-
|
|
112
|
-
if (answer.trim()) {
|
|
113
|
-
// Update .env file
|
|
114
|
-
let envContent = readFileSync(envPath, 'utf-8');
|
|
115
|
-
envContent = envContent.replace(/EIA_API_KEY=.*/g, `EIA_API_KEY=${answer.trim()}`);
|
|
116
|
-
writeFileSync(envPath, envContent);
|
|
117
|
-
|
|
118
|
-
// Update process.env
|
|
119
|
-
process.env.EIA_API_KEY = answer.trim();
|
|
120
|
-
|
|
121
|
-
console.log(chalk.green('β API key saved to .env'));
|
|
122
|
-
} else {
|
|
123
|
-
console.log(chalk.yellow('β οΈ Running without EIA API key (will use fallback data sources)'));
|
|
124
|
-
}
|
|
125
|
-
}
|
|
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'));
|
|
126
115
|
}
|
|
127
116
|
|
|
128
117
|
/**
|
|
129
118
|
* Main CLI function
|
|
130
119
|
*/
|
|
131
120
|
async function main(options) {
|
|
132
|
-
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'));
|
|
133
123
|
|
|
134
124
|
try {
|
|
135
125
|
// Auto-configure environment
|
|
@@ -182,49 +172,19 @@ async function main(options) {
|
|
|
182
172
|
const detectedLocation = await getLocation();
|
|
183
173
|
locationSpinner.succeed(chalk.green(`π Detected Location: ${detectedLocation}`));
|
|
184
174
|
|
|
185
|
-
// Ask user to confirm or override (
|
|
175
|
+
// Ask user to confirm or override (no timeout - wait for input)
|
|
186
176
|
console.log(chalk.blue('\nYou can use this location or enter a custom one.'));
|
|
187
|
-
console.log(chalk.gray('(Press Enter to use detected location, or type custom location)'));
|
|
188
|
-
console.log(chalk.gray('You have 60 seconds to respond...'));
|
|
177
|
+
console.log(chalk.gray('(Press Enter to use detected location, or type a custom location like "Dallas,TX,USA")'));
|
|
189
178
|
|
|
190
179
|
try {
|
|
191
|
-
|
|
192
|
-
let hasResolved = false;
|
|
193
|
-
|
|
194
|
-
// Create a promise that auto-resolves after 60 seconds
|
|
195
|
-
const timeoutPromise = new Promise((resolve) => {
|
|
196
|
-
timeoutId = setTimeout(() => {
|
|
197
|
-
if (!hasResolved) {
|
|
198
|
-
hasResolved = true;
|
|
199
|
-
console.log(chalk.yellow('\nβ±οΈ Timeout - using detected location...'));
|
|
200
|
-
resolve('__TIMEOUT__');
|
|
201
|
-
}
|
|
202
|
-
}, 60000); // 60 seconds for npx readline delay
|
|
203
|
-
});
|
|
180
|
+
const customLocation = await question('Enter location (or press Enter for auto-detected): ');
|
|
204
181
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
return answer;
|
|
210
|
-
}
|
|
211
|
-
return '__TIMEOUT__'; // If timeout already occurred, ignore this answer
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
const customLocation = await Promise.race([questionPromise, timeoutPromise]);
|
|
215
|
-
|
|
216
|
-
// If timeout occurred, use detected location
|
|
217
|
-
if (customLocation === '__TIMEOUT__') {
|
|
218
|
-
location = detectedLocation;
|
|
219
|
-
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}`));
|
|
220
186
|
} else {
|
|
221
|
-
|
|
222
|
-
location = customLocation.trim() || detectedLocation;
|
|
223
|
-
if (customLocation.trim()) {
|
|
224
|
-
console.log(chalk.green(`β Using custom location: ${location}`));
|
|
225
|
-
} else {
|
|
226
|
-
console.log(chalk.green(`β Using detected location: ${location}`));
|
|
227
|
-
}
|
|
187
|
+
console.log(chalk.green(`β Using detected location: ${location}`));
|
|
228
188
|
}
|
|
229
189
|
} catch (error) {
|
|
230
190
|
console.log(chalk.yellow(`\nβ οΈ Prompt error, using detected location: ${detectedLocation}`));
|
|
@@ -293,24 +253,31 @@ async function runQueryCycle(wallet, agentName, location, options) {
|
|
|
293
253
|
console.log(chalk.cyan.bold(`π Run #${totalRuns} - ${new Date().toLocaleString()}`));
|
|
294
254
|
console.log(chalk.cyan(`ββββββββββββββββββββββββββββββββββββββββ\n`));
|
|
295
255
|
|
|
296
|
-
// Fetch
|
|
297
|
-
const
|
|
298
|
-
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;
|
|
299
259
|
|
|
300
260
|
try {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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`));
|
|
306
277
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
} catch (fallbackError) {
|
|
311
|
-
dataSpinner.fail(chalk.red('All data sources failed'));
|
|
312
|
-
throw new Error('Unable to fetch energy data from any source');
|
|
313
|
-
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
weatherSpinner.fail(chalk.red('Failed to fetch weather data'));
|
|
280
|
+
throw new Error(`Unable to generate pricing simulation: ${error.message}`);
|
|
314
281
|
}
|
|
315
282
|
|
|
316
283
|
// Run optimization
|
|
@@ -319,12 +286,31 @@ async function runQueryCycle(wallet, agentName, location, options) {
|
|
|
319
286
|
const savings = calculateSavings(energyData, cheapestWindow);
|
|
320
287
|
optSpinner.succeed(chalk.green('Optimization complete'));
|
|
321
288
|
|
|
322
|
-
// Display results
|
|
289
|
+
// Display results with intelligent insights
|
|
323
290
|
console.log(chalk.green.bold('\n⨠Optimization Results:'));
|
|
324
291
|
console.log(chalk.white(` Cheapest charge window: ${cheapestWindow.timeWindow}`));
|
|
325
292
|
console.log(chalk.white(` Price: $${cheapestWindow.price.toFixed(4)}/kWh`));
|
|
326
293
|
console.log(chalk.white(` Savings: ${savings.toFixed(1)}%`));
|
|
327
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
|
+
|
|
328
314
|
// Prepare submission data
|
|
329
315
|
const submissionData = {
|
|
330
316
|
agent_name: agentName,
|
|
@@ -392,6 +378,95 @@ async function runQueryCycle(wallet, agentName, location, options) {
|
|
|
392
378
|
console.log(chalk.magenta(`\nβ Earned ${totalPointsEarned} points! (${basePoints} base${bonusPoints > 0 ? ` + ${bonusPoints} bonus` : ''})`));
|
|
393
379
|
console.log(chalk.magenta(`β Total Points: ${currentPoints}`));
|
|
394
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
|
+
|
|
395
470
|
// Premium upgrade option
|
|
396
471
|
if (options.premium && totalRuns % 3 === 0) {
|
|
397
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": "",
|