Inspired by the excellent work of Amber Enphase Zero Export Switcher Tool.
This implementation is written in TypeScript and deployed to AWS as a single-file Lambda, scheduled to run via EventBridge Scheduler. It automatically toggles your battery-less Enphase grid profile to prevent exporting when Amber Electric feed-in prices are negative.
Avoid getting charged for exporting during negative price events.
After multiple attempts, I couldn’t get the Amber Enphase Zero Export Switcher Tool to work. Both Enphase support and my solar installer confirmed that adding another grid profile is not possible.
Having requested DIY installer access via the Enphase Service Manager, I discovered that the Grid Profile can be changed through the Service Manager interface. The main challenge was implementing programmatic authentication. Once authenticated, it was straightforward to inspect the API requests and replicate them programmatically.
- Fetch current import/export prices from Amber.
- Decide whether exporting “costs” you (negative FiT).
- Set Enphase grid profile to zero-export when it’s costly; otherwise restore normal export.
- The Enphase grid profile is cached in DynamoDB to minimize unnecessary API calls.
- Runs every 15 minutes between 9:00–17:00 Australia/Sydney time. Enphase takes a long time to apply grid profile change. Longer intervals allows time for Enphase to change the rid profile.
- Adjust the battery reserve level to 100% at the same time you switch to the 0 export grid profile. Immediately change it back to the normal reserve level.
If the Tesla battery is not fully charge, when Enphase grid profile is changed to zero export. Enphase stops charging the battery and starts to power the house using the battery. To avoid this, Telsa battery's reserve needs to be changed to 100%. After it is fully charged change it back to its original value.
Telsa provides fleet-api access the Telsa powerwall.
- Create a Tesla developer account
- Create a new app
- Add url
- Lambda (Node 20, CJS handler
index.handler) bundled via esbuild todist/index.js. - EventBridge Scheduler with timezone set to Australia/Sydney.
- Pulumi TypeScript stack under
infra/provisions IAM, Lambda, and schedule.
- Node 20+, npm
- Pulumi CLI installed and logged in
- AWS credentials configured for your target account/region
- Install dependencies
npm i
cd infra && npm i && cd ..- Configure environment
Create
.envfrom the example and fill values:
AMBER_TOKEN=
AMBER_SITE_ID=
ENPHASE_EMAIL=
ENPHASE_PASSWORD=
ENPHASE_SYSTEM_ID=
ENPHASE_SERIAL_NUMBER=
ENPHASE_PART_NUMBER=
ENPHASE_GRID_PROFILE_NAME_ZERO_EXPORT_ID=
ENPHASE_GRID_PROFILE_NAME_NORMAL_EXPORT_ID=- Build Lambda bundle
npm run build # outputs dist/index.js with exported handler- Configure Pulumi
cd infra
pulumi stack init prod # or: pulumi stack select prod
pulumi config set aws:region ap-southeast-2
# Map .env values into Pulumi config (UPPERCASE keys)
sh scripts/set-pulumi-config-from-env.sh
# verify config
pulumi config- Deploy
pulumi upOutputs:
pulumi stack output functionName
pulumi stack output scheduleArnnpm run startnpm run build
cd infra && pulumi upcd infra
pulumi destroy- If your shell complains about stack names (zsh globbing), quote them:
pulumi up --stack 'prod'. - If IAM permission errors occur, ensure the Scheduler role has
lambda:InvokeFunctionon the function (managed by Pulumi ininfra/index.ts). - The schedule uses EventBridge Scheduler with
scheduleExpressionTimezone: "Australia/Sydney"andcron(0/10 10-16 ? * * *). - Lint/format:
npm run lint
npm run format
