Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate with an ISO to receive grid signals #79

Closed
shankari opened this issue Oct 17, 2024 · 19 comments · Fixed by #91
Closed

Integrate with an ISO to receive grid signals #79

shankari opened this issue Oct 17, 2024 · 19 comments · Fixed by #91
Assignees

Comments

@shankari
Copy link
Collaborator

Since CharIN is in California, we will want to integrate with the California MIDAS API
https://www.energy.ca.gov/publications/2021/market-informed-demand-automation-server-midas-documentation-version-12

Design considerations:

  • Language: Their existing examples are in python, R, curl and csharp. Our potential CSMSes use go (MaEVe) and javascript (Citrine)
  • Authentication: username + password based (can be used for a single script), or cert based

Given the time frame, I would suggest that we hack together something with username + password, and curl to pull data and send it to the CSMS.

Can refine further once that is done

@shankari shankari self-assigned this Oct 17, 2024
@shankari shankari added this to the CharIN demo prep milestone Oct 17, 2024
@shankari
Copy link
Collaborator Author

I will do this after #78

@shankari
Copy link
Collaborator Author

Now that we have cleared the decks with #88, getting started on this.
Let's first add a UI version of the manual clamp since we didn't copy that script over

@shankari
Copy link
Collaborator Author

I think I have the hang of NodeRed now and have created a basic flow that sets the start of the charge profile and sends it over to the CSMS

Screenshot 2024-11-16 at 12 39 04 PM

However, the CSMS does not appear to be sending the information over to the station, apparently because SetChargingProfile is not implemented.

2024-11-16 12:36:15 time=2024-11-16T20:36:15.289Z level=INFO msg="POST /api/v0/cs/cp001/setchargingprofile" remote_addr=192.168.65.1:35315 status=201 bytes=0 duration=3.492473ms
2024-11-16 12:36:15 time=2024-11-16T20:36:15.351Z level=ERROR msg="unable to route message" chargeStationId=cp001 action=SetChargingProfile err="routing request: NotImplemented: SetChargingProfile result not implemented"
2024-11-16 12:36:17 time=2024-11-16T20:36:15.351Z level=ERROR msg="cs/in/ocpp2.0.1/# receive" duration=159.807µs messaging.system=mqtt messaging.consumer.id=manager-pyJnY messaging.message.payload_size_bytes=477 messaging.operation=receive csId=cp001 ocpp.version=2.0.1 call_result.action=SetChargingProfile messaging.message.conversation_id=cccf2aa0-f16f-4647-bf05-df20f7ea817e
2024-11-16 12:36:17 time=2024-11-16T20:36:15.352Z level=ERROR msg=exception exception.type=*fmt.wrapError exception.message="routing request: NotImplemented: SetChargingProfile result not implemented"
2024-11-16 12:36:20 time=2024-11-16T20:36:15.286Z level=INFO msg="cs/out/ocpp2.0.1/# publish" duration=2.882475ms messaging.system=mqtt messaging.message.payload_size_bytes=444 messaging.operation=publish messaging.message.conversation_id=cccf2aa0-f16f-4647-bf05-df20f7ea817e csId=cp001 call.action=SetChargingProfile

Double checked that we do in fact check out from the correct branch.

          - csms: maeve
            csms_repo: louisg1337/maeve-csms
            csms_branch: set_charging_profile
            image_name: manager
            context: ./maeve-csms/manager
            host_namespace: ghcr.io/everest/everest-demo


      - name: Checkout the CSMS repo
        uses: actions/checkout@v4
        with:
            repository: ${{ matrix.csms_repo }}
            ref: ${{ matrix.csms_branch }}
            path: ${{ matrix.csms }}-csms

Investigating further...

shankari pushed a commit to US-JOET/maeve-csms that referenced this issue Nov 16, 2024
So we can see why `SetChargingProfile` is not implemented
EVerest/everest-demo#79 (comment)
@shankari
Copy link
Collaborator Author

This is super hard to debug because I can't build the images locally. However, launching an existing container (with modules downloaded) and building in it works.

Changes to enable this hacky build:
enable_maeve_editing.patch

I can then run CGO_ENABLED=0 go build -o /app main.go to compile and /app serve -c /config/config.toml to run.

Using this to enable logging, I see this comparison.
time=2024-11-16T23:00:51.704Z level=INFO msg="cs/out/ocpp2.0.1/# publish" duration=108.576µs messaging.system=mqtt messaging.message.payload_size_bytes=98 messaging.operation=publish messaging.message.conversation_id=ebbec2cc-393a-4309-877b-33d44718d349 csId=cp001 call_result.action=StatusNotification
time=2024-11-16T23:00:56.456Z level=INFO msg="[API TRACE] in charging middleware!"
time=2024-11-16T23:00:56.456Z level=INFO msg="[API TRACE] In server.go, SetChargingProfile()"
time=2024-11-16T23:00:56.456Z level=INFO msg="[API TRACE] req:" !BADKEY="&{ChargingProfileKind:Absolute ChargingProfilePurpose:ChargingStationMaxProfile ChargingSchedule:[{ChargingRateUnit:A ChargingSchedulePeriod:[{CustomData:<nil> Limit:10 NumberPhases:0xc000f9e100 PhaseToUse:<nil> StartPeriod:0}] CustomData:<nil> Duration:0xc000f9e108 Id:0 MinChargingRate:0xc000f9e118 SalesTariff:<nil> StartSchedule:0xc000cacea0}] CustomData:<nil> Id:2000 RecurrencyKind:<nil> StackLevel:0 TransactionId:<nil> ValidFrom:<nil> ValidTo:<nil>}"
time=2024-11-16T23:00:56.459Z level=INFO msg="[API TRACE] we are in Send() in call_maker.go" action=SetChargingProfile
time=2024-11-16T23:00:56.460Z level=INFO msg="sending message" action=SetChargingProfile chargeStationId=cp001
time=2024-11-16T23:00:56.461Z level=INFO msg="POST /api/v0/cs/cp001/setchargingprofile" remote_addr=192.168.65.1:42545 status=201 bytes=0 duration=5.019434ms
time=2024-11-16T23:00:56.557Z level=INFO msg="[API TRACE] we are in route() in router.go" action=SetChargingProfile
time=2024-11-16T23:00:56.557Z level=INFO msg="[API TRACE] we are in route() in router.go, in MessageTypeCallResult" route="{NewRequest:<nil> NewResponse:<nil> RequestSchema: ResponseSchema: Handler:<nil>}"
time=2024-11-16T23:00:56.557Z level=ERROR msg="unable to route message" chargeStationId=cp001 action=SetChargingProfile err="routing request: NotImplemented: SetChargingProfile result not implemented"
time=2024-11-16T23:00:56.557Z level=ERROR msg="cs/in/ocpp2.0.1/# receive" duration=579.707µs messaging.system=mqtt messaging.consumer.id=manager-kbxkb messaging.message.payload_size_bytes=477 messaging.operation=receive csId=cp001 ocpp.version=2.0.1 call_result.action=SetChargingProfile messaging.message.conversation_id=b5de9e86-ee92-4b23-8f2b-7192f705e5f2
time=2024-11-16T23:00:56.557Z level=ERROR msg=exception exception.type=*fmt.wrapError exception.message="routing request: NotImplemented: SetChargingProfile result not implemented"

an example of a successful run initiated by a script is

time=2024-11-16T23:53:54.030Z level=INFO msg="POST /api/v0/token" remote_addr=192.168.65.1:42597 status=201 bytes=0 duration=4.178824ms

an example of a successful run initiated by the CSMS is

time=2024-11-16T23:54:30.343Z level=INFO msg="GET /api/v0/cs/cp001/auth" remote_addr=[2001:db8:a::5]:47104 status=200 bytes=123 duration=2.995971ms
time=2024-11-16T23:54:30.346Z level=INFO msg="[API TRACE] we are in route() in router.go" action=BootNotification
time=2024-11-16T23:54:30.346Z level=INFO msg="[API TRACE] we are in route() in router.go, in MessageTypeCall" route="{NewRequest:0xbb5b80 RequestSchema:ocpp201/BootNotificationRequest.json ResponseSchema:ocpp201/BootNotificationResponse.json Handler:{Clock:{} RuntimeDetailsStore:0xc0005c2060 HeartbeatInterval:300}}"
time=2024-11-16T23:54:30.406Z level=INFO msg="[API TRACE] we are in route() in router.go" action=SecurityEventNotification
time=2024-11-16T23:54:30.406Z level=INFO msg="[API TRACE] we are in route() in router.go, in MessageTypeCall" route="{NewRequest:0xbb5f40 RequestSchema:ocpp201/SecurityEventNotificationRequest.json ResponseSchema:ocpp201/SecurityEventNotificationResponse.json Handler:{}}"
time=2024-11-16T23:54:30.412Z level=INFO msg="[API TRACE] we are in route() in router.go" action=StatusNotification
time=2024-11-16T23:54:30.412Z level=INFO msg="[API TRACE] we are in route() in router.go, in MessageTypeCall" route="{NewRequest:0xbb5e80 RequestSchema:ocpp201/StatusNotificationRequest.json ResponseSchema:ocpp201/StatusNotificationResponse.json Handler:0xbb3900}"
time=2024-11-16T23:54:30.346Z level=INFO msg="cs/in/ocpp2.0.1/# receive" duration=9.045078ms messaging.system=mqtt messaging.consumer.id=manager-rdfoD messaging.message.payload_size_bytes=236 messaging.operation=receive csId=cp001 ocpp.version=2.0.1 call.action=BootNotification messaging.message.conversation_id=1a61fe90-1c37-4c27-b200-207122bfa3d2 request.status=Accepted boot.reason=PowerUp boot.vendor=EVerestVendor boot.model=EVerestModel boot.serial=012345678 boot.firmware=1.0
time=2024-11-16T23:54:30.351Z level=INFO msg="cs/out/ocpp2.0.1/# publish" duration=4.472511ms messaging.system=mqtt messaging.message.payload_size_bytes=167 messaging.operation=publish messaging.message.conversation_id=1a61fe90-1c37-4c27-b200-207122bfa3d2 csId=cp001 call_result.action=BootNotification
time=2024-11-16T23:54:30.406Z level=INFO msg="cs/in/ocpp2.0.1/# receive" duration=639.355µs messaging.system=mqtt messaging.consumer.id=manager-rdfoD messaging.message.payload_size_bytes=234 messaging.operation=receive csId=cp001 ocpp.version=2.0.1 call.action=SecurityEventNotification messaging.message.conversation_id=4d610c34-8ef3-4114-8d0a-d6a158096ff8 security_event.timestamp=2024-11-16T23:54:30.345Z security_event.type=StartupOfTheDevice security_event.tech_info="Charging Station powered up! Firmware version: 1.0"

It seems clear that we are trying to forward the message to the charge station. It also seems I am not sure if it is failing in the send or the response, but the BADKEY error seems to argue for the send.

@shankari
Copy link
Collaborator Author

Ok so the !BADKEY is a false alarm - it seems to be printed out as part of any map. But as we add more logs, it is very clear what the problem is -

the CallRoutes map does not list the `SetChargeProfile` entry.
time=2024-11-17T00:30:00.015Z level=INFO msg="[API TRACE] we are in route() in router.go, map of call routes is" !BADKEY="map[
- Authorize:{NewRequest:0xbb5b60 RequestSchema:ocpp201/AuthorizeRequest.json ResponseSchema:ocpp201/AuthorizeResponse.json Handler:{TokenAuthService:0xc0003b8f00 CertificateValidationService:0xc0003b8da0}}
- BootNotification:{NewRequest:0xbb5bc0 RequestSchema:ocpp201/BootNotificationRequest.json ResponseSchema:ocpp201/BootNotificationResponse.json Handler:{Clock:{} RuntimeDetailsStore:0xc0003325a0 HeartbeatInterval:300}}
- FirmwareStatusNotification:{NewRequest:0xbb5c20 RequestSchema:ocpp201/FirmwareStatusNotificationRequest.json ResponseSchema:ocpp201/FirmwareStatusNotificationResponse.json Handler:{}}
- Get15118EVCertificate:{NewRequest:0xbb5ce0 RequestSchema:ocpp201/Get15118EVCertificateRequest.json ResponseSchema:ocpp201/Get15118EVCertificateResponse.json Handler:{ContractCertificateProvider:0xc0007199e0}}
- GetCertificateStatus:{NewRequest:0xbb5c80 RequestSchema:ocpp201/GetCertificateStatusRequest.json ResponseSchema:ocpp201/GetCertificateStatusResponse.json Handler:{CertificateValidationService:0xc0003b8da0}}
- Heartbeat:{NewRequest:0xbb5d40 RequestSchema:ocpp201/HeartbeatRequest.json ResponseSchema:ocpp201/HeartbeatResponse.json Handler:{Clock:{}}}
- LogStatusNotification:{NewRequest:0xbb5da0 RequestSchema:ocpp201/LogStatusNotificationRequest.json ResponseSchema:ocpp201/LogStatusNotificationResponse.json Handler:{}}
- MeterValues:{NewRequest:0xbb5e00 RequestSchema:ocpp201/MeterValuesRequest.json ResponseSchema:ocpp201/MeterValuesResponse.json Handler:{}}
- NotifyReport:{NewRequest:0xbb5e60 RequestSchema:ocpp201/NotifyReportRequest.json ResponseSchema:ocpp201/NotifyReportResponse.json Handler:{}}
- SecurityEventNotification:{NewRequest:0xbb5f80 RequestSchema:ocpp201/SecurityEventNotificationRequest.json ResponseSchema:ocpp201/SecurityEventNotificationResponse.json Handler:{}}
- SignCertificate:{NewRequest:0xbb5f20 RequestSchema:ocpp201/SignCertificateRequest.json ResponseSchema:ocpp201/SignCertificateResponse.json Handler:{ChargeStationCertificateProvider:0xc0003b8dc0 Store:0xc0003325a0}}
- StatusNotification:{NewRequest:0xbb5ec0 RequestSchema:ocpp201/StatusNotificationRequest.json ResponseSchema:ocpp201/StatusNotificationResponse.json Handler:0xbb3940} TransactionEvent:{NewRequest:0xbb5fe0 RequestSchema:ocpp201/TransactionEventRequest.json ResponseSchema:ocpp201/TransactionEventResponse.json Handler:{Store:0xc0003325a0 TokenAuthService:0xc0003b8f60 TariffService:{}}
}]"

But I checked the code, and it is not defined https://github.com/thoughtworks/maeve-csms/pull/44/files#diff-2e87aed153ea3c66a759c947e51d51ec1b0275802fc12e8f987c0d570d2c03c7
so I am not sure how it ever worked.

Let's quickly check the charin_e2e_demo branch and see if we had any other changes there.

@the-bay-kay are you sure this worked for you? Do you still have the image/container that you tested against? It would be good to check the code and copy it over as additional patches...

@shankari
Copy link
Collaborator Author

I tried to run using the instructions here #74 (comment)
and I can't build because of the go mod issue. Trying on my personal laptop...

@shankari
Copy link
Collaborator Author

My personal laptop is super slow (maybe even slower than the work laptop that @Abby-Wheelis has. So it is still building the maeve images. But I checked the call map and can verify that there is no additional code. Writing it now...

@shankari
Copy link
Collaborator Author

Ok, so this appears to be an issue with EVerest (phew!, I am not crazy). The error that we were getting was while handling the response from the setChargingProfile. That is why the handler that is defined is the
manager/handlers/ocpp201/set_charging_profile_result.go

We should still define it, but its absence should not affect the message sent to the station. If we clear out the gateway logs and then send the message again, we see that it does in fact send a websock message and receive a response, which it tries to send to us.

Let's add some additional logs in the gateway to validate this, and then see what is happening on the station...

2024-11-16 18:19:06 2024/11/17 02:19:06 INFO cs/out/ocpp2.0.1/# receive duration=34.912µs messaging.system=mqtt messaging.message.payload_size_bytes=444 messaging.message.conversation_id=a8ea338e-3304-443e-8023-b78ac85cf983 messaging.operation=receive csId=cp001
2024-11-16 18:19:06 2024/11/17 02:19:06 INFO ocpp2.0.1 publish duration=85.405µs messaging.system=websocket messaging.message.payload_size_bytes=413 messaging.operation=publish messaging.message.conversation_id=a8ea338e-3304-443e-8023-b78ac85cf983 csId=cp001
2024-11-16 18:19:06 2024/11/17 02:19:06 INFO ocpp2.0.1 receive duration=40.637µs messaging.system=websocket messaging.operation=receive messaging.message.payload_size_bytes=64 csId=cp001 messaging.message.conversation_id=a8ea338e-3304-443e-8023-b78ac85cf983
2024-11-16 18:19:06 2024/11/17 02:19:06 INFO cs/in/ocpp2.0.1/# publish duration=89.829µs messaging.system=mqtt messaging.message.payload_size_bytes=477 messaging.operation=publish messaging.message.conversation_id=a8ea338e-3304-443e-8023-b78ac85cf983 csId=cp001

@shankari
Copy link
Collaborator Author

Ok, so it looks like it was actually working?! We just didn't notice it because apparently that is not being logged on the charger?! Let's take a look at the logging on the charger, and also see if we can connect to its MQTT bus so we can see that the value has been received.

time=2024-11-17T02:44:44.348Z level=INFO msg="[API TRACE] we are in route() in router.go, request payload is" !BADKEY="{\"evseId\":0,\"chargingProfile\":{\"chargingProfileKind\":\"Absolute\",\"chargingProfilePurpose\":\"ChargingStationMaxProfile\",\"chargingSchedule\":[{\"chargingRateUnit\":\"A\",\"chargingSchedulePeriod\":[{\"limit\":10,\"numberPhases\":3,\"startPeriod\":0}],\"duration\":14400,\"id\":0,\"minChargingRate\":0,\"startSchedule\":\"2024-11-08T19:00:00.000Z\"}],\"id\":2000,\"stackLevel\":0}}"
time=2024-11-17T02:44:44.348Z level=INFO msg="[API TRACE] we are in route() in router.go, response payload is" !BADKEY="{\"status\":\"Accepted\"}"

shankari pushed a commit to US-JOET/maeve-csms that referenced this issue Nov 17, 2024
Which is currently a NOP, but we want to register it in the map so that it
doesn't error out. This fixes EVerest/everest-demo#79 (comment)
@shankari
Copy link
Collaborator Author

shankari commented Nov 17, 2024

The additional logging to show when we received the profile is in manager/demo-patches/enable_ocpp_logging.patch
Let's see why it is not showing up...

Patch has been applied properly; let's bump it up to ERROR to see if it shows up

@shankari
Copy link
Collaborator Author

Verified that after bumping it up to ERROR, we do see it. But we see other INFO messages from OCPP201. Let's see why this is the case. Did we not compile after making the change?

2024-11-17 03:23:50.189271 [ERRO] ocpp:OCPP201    void ocpp::v201::ChargePoint::handle_set_charging_profile_req(ocpp::Call<ocpp::v201::SetChargingProfileRequest>) :: Received SetChargingProfileRequest: {
    "chargingProfile": {
        "chargingProfileKind": "Absolute",
        "chargingProfilePurpose": "ChargingStationMaxProfile",
        "chargingSchedule": [
            {
                "chargingRateUnit": "A",
                "chargingSchedulePeriod": [
                    {
                        "limit": 10.0,
                        "numberPhases": 3,
                        "startPeriod": 0
                    }
                ],
                "duration": 14400,
                "id": 0,
                "minChargingRate": 0.0,
                "startSchedule": "2024-11-08T19:00:00.000Z"
            }
        ],
        "id": 2000,
        "stackLevel": 0
    },
    "evseId": 0
}
with messageId: 166968a6-c0c9-43f3-b30f-0543d321e87e
2024-11-17 03:23:50.196288 [ERRO] ocpp:OCPP201    void ocpp::v201::ChargePoint::handle_set_charging_profile_req(ocpp::Call<ocpp::v201::SetChargingProfileRequest>) :: Accepting SetChargingProfileRequest

@shankari
Copy link
Collaborator Author

When rebuilding after configuring libocpp, it looks like it was still stuck at ERROR. Need to investigate this, but moving on finish the other changes first.

@shankari
Copy link
Collaborator Author

I just recreated all the containers, so checking this again...

  1. They are all now at info EVLOG_info << "Received SetChargingProfileRequest: " << call.msg << "\nwith messageId: " << call.uniqueId;
  2. compiling; everything seems fine
-- Configuring done
-- Generating done
-- Build files have been written to: /ext/build
ninja: Entering directory `/ext/build'
ninja: no work to do.
  1. installing (ah this is missing in the dockerfile!!)
2024-11-17 09:27:04.618864 [INFO] ocpp:OCPP201     :: Received SetChargingProfileRequest: {
    "chargingProfile": {
        "chargingProfileKind": "Absolute",
        "chargingProfilePurpose": "ChargingStationMaxProfile",
        "chargingSchedule": [
            {
                "chargingRateUnit": "A",
                "chargingSchedulePeriod": [
                    {
                        "limit": 20.0,
                        "numberPhases": 3,
                        "startPeriod": 0
                    }
                ],
                "duration": 3579,
                "id": 0,
                "minChargingRate": 0.0,
                "startSchedule": "2024-11-17T09:22:21.445Z"
            }
        ],
        "id": 2000,
        "stackLevel": 0
    },
    "evseId": 0
}

Just need to install after compiling!

@shankari
Copy link
Collaborator Author

Basic MIDAS integration done - the scripts at https://github.com/morganmshep/MIDAS-Python-Repository were crude but very helpful and the system as a whole was functioning well. It was also fairly easy to port to javascript/nodered.

HOWEVER, the sample rate schedule does not have any curtailment, only tariffs

{'RateID': 'USCA-TSTS-TTOU-TEST', 
SystemTime_UTC': '2024-11-17T09:35:04.270Z',
'RateName': 'CEC TEST24HTOU2',
'RateType': 'Time of use',
''ValueInformation': [
{'ValueName': 'hour1', 'DateStart': '2022-01-01', 'DateEnd': '2032-12-31', 'DayStart': 'Monday', 'DayEnd': 'Holiday', 'TimeStart': '00:00:00', 'TimeEnd': '00:59:59', 'value': 0.215, 'Unit': '$/kWh'},
{'ValueName': 'hour2', 'DateStart': '2022-01-01', 'DateEnd': '2032-12-31', 'DayStart': 'Monday', 'DayEnd': 'Holiday', 'TimeStart': '01:00:00', 'TimeEnd': '01:59:59', 'value': 0.102, 'Unit': '$/kWh'}
...

I tried a different rate schedule (retrieved via GetHistoricalRINList for "PG", "PG"), but that gave me an error.

{'RateID': 'USCA-FLEX-FXHT-0000', 'SignalType': 'Flex Alerts', 'Description': 'Flex Alert Historical Data'}

------ all data ------
Invalid id  = USCA-FLEX-FXHT-0000 was used.

Will see if we can get info from CARB, otherwise, in the interim, will just try to munge the TOU values into pmax.

@shankari
Copy link
Collaborator Author

Moved some things around so that we can display the incoming grid schedule better.
Screenshot 2024-11-17 at 6 25 02 AM

And now with a nice chart
Screenshot 2024-11-17 at 7 05 08 AM

Before munging the schedule from MIDAS and sending it over, let's see if we can get the composite schedule from the station over MQTT and display it

@shankari
Copy link
Collaborator Author

Couple of notes:

the charging schedules seem to show up at `everest/ocpp/ocpp_generic/var`, but it seems like the full list and not the composite
{
  "data": {
    "schedules": [
      {
        "charging_rate_unit": "A",
        "charging_schedule_period": [
          {
            "limit": 48,
            "number_phases": 3,
            "start_period": 0
          }
        ],
        "duration": 600,
        "evse": 0,
        "start_schedule": "2024-11-17T15:30:32.000Z"
      },
      {
        "charging_rate_unit": "A",
        "charging_schedule_period": [
          {
            "limit": 48,
            "number_phases": 3,
            "start_period": 0
          }
        ],
        "duration": 600,
        "evse": 1,
        "start_schedule": "2024-11-17T15:30:32.000Z"
      }
    ]
  },
  "name": "charging_schedules"
}
If we change the max_current slider in the UI, it publishes to `everest/iso15118_charger/charger/cmd`
{
  "data": {
    "args": {
      "max_current": 21.899999618530273
    },
    "id": "c8e1549e-4fc1-4a69-a2c3-eb3d27357a18",
    "origin": "evse_manager_1"
  },
  "name": "update_ac_max_current",
  "type": "call"
}

Hm... but from the UI, it looks like we publish to everest_external/nodered/#/cmd/set_max_current. And yes we do.
I guess something internally listens to it and re-publishes.

searching for "sched", I also find potentially relevant entries in

`everest/evse_manager_1/evse/var` and `everest/evse_manager_1/evse/cmd`
{
  "data": {
    "limits_root_side": {
      "ac_max_current_A": 32,
      "ac_max_phase_count": 3
    },
    "schedule": [
      {
        "limits_to_root": {
          "ac_max_current_A": 32,
          "ac_max_phase_count": 3
        },
        "timestamp": "2024-11-17T15:00:00.000Z"
      },
      {
        "limits_to_root": {
          "ac_max_current_A": 32,
          "ac_max_phase_count": 3
        },
        "timestamp": "2024-11-17T15:45:39.299Z"
      }
    ],
    "uuid": "evse_manager_1",
    "valid_until": "2024-11-17T15:45:56.151Z"
  },
  "name": "enforced_limits"
}

{
  "data": {
    "args": {
      "value": {
        "schedule_import": [
          {
            "limits_to_leaves": {
              "ac_max_current_A": 48,
              "ac_max_phase_count": 3
            },
            "limits_to_root": {},
            "timestamp": "2024-11-17T15:45:39.299Z"
          }
        ]
      }
    },
    "id": "aee7c016-013d-447d-9da7-7ce5275f1198",
    "origin": "ocpp"
  },
  "name": "set_external_limits",
  "type": "call"
}
`everest/grid_connection_point/energy_grid/var` and `everest/grid_connection_point/energy_grid/cmd` and `grid_connection_point` with similar paths
{
  "data": {
    "children": [
      {
        "children": [],
        "energy_usage_root": {
          "current_A": {
            "L1": 0,
            "L2": 0,
            "L3": 0,
            "N": 0
          },
          "energy_Wh_import": {
            "L1": 0,
            "L2": 0,
            "L3": 0,
            "total": 0
          },
          "frequency_Hz": {
            "L1": 50.110260009765625,
            "L2": 50.110260009765625,
            "L3": 50.110260009765625
          },
          "meter_id": "YETI_POWERMETER",
          "phase_seq_error": false,
          "power_W": {
            "L1": 0,
            "L2": 0,
            "L3": 0,
            "total": 0
          },
          "timestamp": "2024-11-17T15:45:44.887Z",
          "voltage_V": {
            "L1": 231.56556701660156,
            "L2": 231.56556701660156,
            "L3": 231.56556701660156
          }
        },
        "evse_state": "Unplugged",
        "node_type": "Evse",
        "priority_request": false,
        "schedule_export": [
          {
            "limits_to_leaves": {},
            "limits_to_root": {
              "ac_max_current_A": 16,
              "ac_max_phase_count": 3,
              "ac_min_current_A": 0,
              "ac_min_phase_count": 1,
              "ac_number_of_active_phases": 3,
              "ac_supports_changing_phases_during_charging": true
            },
            "timestamp": "2024-11-17T15:00:00.000Z"
          }
        ],
        "schedule_import": [
          {
            "limits_to_leaves": {
              "ac_max_current_A": 48,
              "ac_max_phase_count": 3
            },
            "limits_to_root": {
              "ac_max_current_A": 32,
              "ac_max_phase_count": 3,
              "ac_min_current_A": 6,
              "ac_min_phase_count": 1,
              "ac_number_of_active_phases": 3,
              "ac_supports_changing_phases_during_charging": true
            },
            "timestamp": "2024-11-17T15:45:39.299Z"
          }
        ],
        "uuid": "evse_manager_1"
      }
    ],
    "node_type": "Generic",
    "schedule_export": [
      {
        "limits_to_leaves": {
          "ac_max_current_A": 40,
          "ac_max_phase_count": 3
        },
        "limits_to_root": {
          "ac_max_current_A": 40,
          "ac_max_phase_count": 3
        },
        "timestamp": "2024-11-17T15:00:00.000Z"
      }
    ],
    "schedule_import": [
      {
        "limits_to_leaves": {
          "ac_max_current_A": 40,
          "ac_max_phase_count": 3
        },
        "limits_to_root": {
          "ac_max_current_A": 40,
          "ac_max_phase_count": 3
        },
        "timestamp": "2024-11-17T15:00:00.000Z"
      }
    ],
    "uuid": "grid_connection_point"
  },
  "name": "energy_flow_request"
}

{
  "data": {
    "args": {
      "value": {
        "limits_root_side": {
          "ac_max_current_A": 32,
          "ac_max_phase_count": 3
        },
        "schedule": [
          {
            "limits_to_root": {
              "ac_max_current_A": 32,
              "ac_max_phase_count": 3
            },
            "timestamp": "2024-11-17T15:00:00.000Z"
          },
          {
            "limits_to_root": {
              "ac_max_current_A": 32,
              "ac_max_phase_count": 3
            },
            "timestamp": "2024-11-17T15:45:39.299Z"
          }
        ],
        "uuid": "evse_manager_1",
        "valid_until": "2024-11-17T15:45:56.151Z"
      }
    },
    "id": "2c663670-5209-4bf3-b730-f42f2f76bff8",
    "origin": "energy_manager"
  },
  "name": "enforce_limits",
  "type": "call"
}
and of course, ocpp publishes the basic schedules at `everest/ocpp/ocpp_generic/var`
{
  "data": {
    "schedules": [
      {
        "charging_rate_unit": "A",
        "charging_schedule_period": [
          {
            "limit": 48,
            "number_phases": 3,
            "start_period": 0
          }
        ],
        "duration": 600,
        "evse": 0,
        "start_schedule": "2024-11-17T15:45:39.000Z"
      },
      {
        "charging_rate_unit": "A",
        "charging_schedule_period": [
          {
            "limit": 48,
            "number_phases": 3,
            "start_period": 0
          }
        ],
        "duration": 600,
        "evse": 1,
        "start_schedule": "2024-11-17T15:45:39.000Z"
      }
    ]
  },
  "name": "charging_schedules"
}

Need to look through the codebase to see where these are published, what they mean and whether any of them represent the composite schedules.

@shankari
Copy link
Collaborator Author

Looks like every module has an mqtt interface to pub/sub

            if (value.limits_root_side.value().total_power_W.has_value()) {
                mod->mqtt.publish(fmt::format("everest_external/nodered/{}/state/max_watt", mod->config.connector_id),
                                  value.limits_root_side.value().total_power_W.value());

or

    const auto& mqtt = mod->mqtt;
    mqtt.subscribe("everest_external/nodered/" + std::to_string(mod->config.connector_id) + "/carsim/cmd/enable",
                   [this](const std::string& message) {
                   });

or

    serial.signalTelemetry.connect([this](Telemetry t) {
        mqtt.publish("everest_external/umwc/cp_hi", t.cp_hi);
        mqtt.publish("everest_external/umwc/cp_lo", t.cp_lo);
        mqtt.publish("everest_external/umwc/pwm_dc", t.pwm_dc);
        mqtt.publish("everest_external/umwc/relais_on", t.relais_on);

@shankari
Copy link
Collaborator Author

Starting from scratch:

Looking at the published API values, I only see status
(from this->api_base + "ocpp/var/connection_status")

I am not seeing connection schedules from this->api_base + "ocpp/var/charging_schedules"

I also note (as I have before), that the code to publish the composite schedules goes into

void OCPP201::publish_charging_schedules(const std::vector<ocpp::v201::CompositeSchedule>& composite_schedules) {
    const auto everest_schedules = conversions::to_everest_charging_schedules(composite_schedules);
    this->p_ocpp_generic->publish_charging_schedules(everest_schedules);
}   

But I can't see it in the code. The generated above gives me a clue that it may be using autogenerated code. Let's check
in the built environment.

I manually set the schedule through the CSMS, and I still don't see anything in the API topic. `everest/ocpp/ocpp_generic` does show some schedules but they are wrong.
{
  "data": {
    "schedules": [
      {
        "charging_rate_unit": "A",
        "charging_schedule_period": [
          {
            "limit": 20,
            "number_phases": 3,
            "start_period": 0
          }
        ],
        "duration": 600,
        "evse": 0,
        "start_schedule": "2024-11-17T17:30:30.000Z"
      },
      {
        "charging_rate_unit": "A",
        "charging_schedule_period": [
          {
            "limit": 20,
            "number_phases": 3,
            "start_period": 0
          }
        ],
        "duration": 600,
        "evse": 1,
        "start_schedule": "2024-11-17T17:30:30.000Z"
      }
    ]
  },
  "name": "charging_schedules"
}

Let's try to edit to make it composite. After trying to set the current to 10,

{"id":2000
"chargingProfileKind":"Absolute"
"chargingProfilePurpose":"ChargingStationMaxProfile"
"chargingSchedule":[{"id":0
    "chargingRateUnit":"A"
    "chargingSchedulePeriod":[{"limit":10
    "numberPhases":3
"startPeriod":0}]
"duration":3600
"minChargingRate":0
"startSchedule":"2024-11-17T17:45:00.000Z"}]
"stackLevel":0}

we end up getting the following, which is clearly wrong.

{
  "data": {
    "schedules": [
      {
        "charging_rate_unit": "A",
        "charging_schedule_period": [
          {
            "limit": 48,
            "number_phases": 3,
            "start_period": 0
          }
        ],
        "duration": 600,
        "evse": 0,
        "start_schedule": "2024-11-17T17:34:00.000Z"
      },
      {
        "charging_rate_unit": "A",
        "charging_schedule_period": [
          {
            "limit": 48,
            "number_phases": 3,
            "start_period": 0
          }
        ],
        "duration": 600,
        "evse": 1,
        "start_schedule": "2024-11-17T17:34:00.000Z"
      }
    ]
  },
  "name": "charging_schedules"
}

Let's print out some composite schedules and figure out what is going on...

@shankari
Copy link
Collaborator Author

Composite schedule calculations appears to be completely messed up, unless I am misunderstanding how it is supposed to work. It works for one single clamp but appears to fail completely once we have a second, overlapping clamp. I don't have time to investigate this now (I need to finish the grid integration and then take a look at the power dial and maybe even SP2/SP3. So filing a new, follow up issue to track that and coordinate with the community (#90)

Turns out this was mainly a false alarm (#90 (comment)) so let's wrap this up and then see what's going on with the power meter.

shankari pushed a commit to US-JOET/everest-demo that referenced this issue Nov 18, 2024
- Login to MIDAS with username and password
- Get token
- Use token to retrive all rates
- Display the retrieved rates in a table

Related: EVerest#79 (comment)

Testing done:
- Ran flow and confirmed that the table showed data

Signed-off-by: Shankari <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant