Stored Procedure return unwanted cursor result
Instead of using a cursor*, write the update and insert operations explicitly as set-based operations:

CREATE OR ALTER PROCEDURE cache.MoveInverterData
(
    @sourceInverterID bigint, 
    @from datetime2(7)
)
AS   
BEGIN
    SET XACT_ABORT, NOCOUNT ON;

    DECLARE @RowsAffected integer = 0;

    -- TODO: Add error handling

    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    BEGIN TRANSACTION;

        -- Update existing rows
        UPDATE CID
        SET [Status] = DID.[Status]
        FROM [data].InverterData AS DID
        JOIN cache.InverterData AS CID
                WITH (SNAPSHOT)
            ON CID.InverterID = DID.InverterID
            AND CID.[Timestamp] = DID.[Timestamp]
        WHERE
            DID.InverterID = @sourceInverterID
            AND DID.[Timestamp] &gt;= @from;

        SET @RowsAffected += @@ROWCOUNT;

        -- Insert new rows
        INSERT cache.InverterData
            (InverterID, [Timestamp], [Status])
        SELECT
            DID.InverterID,
            DID.[Timestamp],
            DID.[Status]
        FROM [data].InverterData AS DID
        WHERE
            DID.InverterID = @sourceInverterID
            AND DID.[Timestamp] &gt;= @from
            AND NOT EXISTS
            (
                SELECT 1
                FROM cache.InverterData AS CID
                    WITH (SNAPSHOT)
                WHERE
                    CID.InverterID = DID.InverterID
                    AND CID.[Timestamp] = DID.[Timestamp]
            );

        SET @RowsAffected += @@ROWCOUNT;

    COMMIT TRANSACTION;

    -- TODO: Use the @RowsAffected result
END;


Ensure both tables have a (non-hash) index on InverterID, [Timestamp].

* Unlike some other database engines, cursors are usually quite inefficient in SQL Server. The overhead and per-row operations almost always make a set-based solution faster and more efficient.