add shading

This commit is contained in:
woheller69 2023-04-06 10:12:17 +02:00
parent 83cc2dae9d
commit e9cb25471e
14 changed files with 193 additions and 20 deletions

View file

@ -19,8 +19,10 @@ public class SolarPowerPlant {
double inverterEfficiency;
double azimuthAngle;
double tiltAngle;
private int[] shadingElevation;
private int[] shadingOpacity;
public SolarPowerPlant(double latitude, double longitude, double cellsMaxPower, double cellsArea, double cellsEfficiency, double diffuseEfficiency, double inverterPowerLimit, double inverterEfficiency, double azimuthAngle, double tiltAngle) {
public SolarPowerPlant(double latitude, double longitude, double cellsMaxPower, double cellsArea, double cellsEfficiency, double diffuseEfficiency, double inverterPowerLimit, double inverterEfficiency, double azimuthAngle, double tiltAngle, int[] shadingElevation, int[] shadingOpacity ) {
this.latitude = latitude;
this.longitude = longitude;
this.cellsMaxPower = cellsMaxPower;
@ -31,6 +33,8 @@ public class SolarPowerPlant {
this.inverterEfficiency = inverterEfficiency / 100;
this.azimuthAngle = azimuthAngle;
this.tiltAngle = tiltAngle;
this.shadingElevation = shadingElevation;
this.shadingOpacity = shadingOpacity;
}
@ -51,14 +55,21 @@ public class SolarPowerPlant {
Double[] normalPanel = {Math.sin(azimuthAngle / 180 * Math.PI) * Math.cos((90 - tiltAngle) / 180 * Math.PI), Math.cos(azimuthAngle / 180 * Math.PI) * Math.cos((90 - tiltAngle) / 180 * Math.PI), Math.sin((90 - tiltAngle) / 180 * Math.PI)};
double efficiency = 0; //calculate scalar product of sunDirection and normalPanel vectors
for (int j = 0; j < directionSun.length; j++) {
efficiency += directionSun[j] * normalPanel[j];
if(solarPowerNormal>0) { //only needed if normal radiation is available
for (int j = 0; j < directionSun.length; j++) {
efficiency += directionSun[j] * normalPanel[j];
}
efficiency = Math.max(0, efficiency); //scalar product is negative if sun points to back of module. set 0 in this case
if (efficiency > 0) {
//Calculate shading in 10 degree ranges, total 36 ranges
int shadingIndex = ((((int) Math.round((solarAzimuth + 5) / 10)) - 1) % 36 + 36) % 36;
if (shadingElevation[shadingIndex] > solarElevation) {
efficiency *= (double) (100 - shadingOpacity[shadingIndex])/100;
}
}
}
efficiency = Math.max(0,efficiency); //scalar product is negative if sun points to back of module. set 0 in this case
//TODO solarPowerDiffuse ignored so far
double dcPower = (solarPowerNormal * efficiency + solarPowerDiffuse * diffuseEfficiency )* cellsEfficiency * cellsArea;
double acPower = Math.min(dcPower * inverterEfficiency, inverterPowerLimit);

View file

@ -10,11 +10,16 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.ItemTouchHelper;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import org.woheller69.weather.R;
@ -22,6 +27,7 @@ import org.woheller69.weather.database.City;
import org.woheller69.weather.database.CityToWatch;
import org.woheller69.weather.database.SQLiteHelper;
import org.woheller69.weather.dialogs.AddLocationDialogOmGeocodingAPI;
import org.woheller69.weather.ui.Help.InputFilterMinMax;
import org.woheller69.weather.ui.RecycleList.RecyclerItemClickListener;
import org.woheller69.weather.ui.RecycleList.RecyclerOverviewListAdapter;
import org.woheller69.weather.ui.RecycleList.SimpleItemTouchHelperCallback;
@ -111,11 +117,66 @@ public class ManageLocationsActivity extends NavigationActivity {
}
private void editCityToWatch(CityToWatch city) {
int[] shadingElevation = city.getShadingElevation();
int[] shadingOpacity = city.getShadingOpacity();
TextView[] textViews = new TextView[shadingElevation.length];
EditText[] elevationViews = new EditText[shadingElevation.length];
EditText[] opacityViews = new EditText[shadingElevation.length];
AlertDialog.Builder alert = new AlertDialog.Builder(context);
LayoutInflater inflater = getLayoutInflater();
View dialogView = inflater.inflate(R.layout.dialog_edit_location, null);
ViewGroup shading = (ViewGroup) dialogView.findViewById(R.id.edit_Location_shading);
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT);
p.weight = 1;
LinearLayout header = new LinearLayout(this);
TextView headerRange = new TextView(this);
TextView headerMinElevation = new TextView(this);
TextView headerOpacity = new TextView(this);
headerRange.setText(R.string.edit_location_shading_azimuth_heading);
headerRange.setPadding(5,0,5,0);
headerMinElevation.setText(R.string.edit_location_shading_solar_elevation_heading);
headerMinElevation.setPadding(5,0,5,0);
headerOpacity.setText(R.string.edit_location_shading_opacity_heading);
headerOpacity.setPadding(5,0,5,0);
headerRange.setLayoutParams(p);
headerMinElevation.setLayoutParams(p);
headerOpacity.setLayoutParams(p);
header.addView(headerRange);
header.addView(headerMinElevation);
header.addView(headerOpacity);
shading.addView(header);
LinearLayout[] container = new LinearLayout[shadingElevation.length];
for (int i = 0; i < shadingElevation.length; i++) {
container[i] = new LinearLayout(this);
container[i].setOrientation(LinearLayout.HORIZONTAL);
textViews[i] = new TextView(this);
opacityViews[i] = new EditText(this);
elevationViews[i] = new EditText(this);
textViews[i].setText("[" + (i*10) +","+ (i*10+10)+"]");
textViews[i].setTextSize(18);
elevationViews[i].setText(Integer.toString(shadingElevation[i]));
elevationViews[i].setInputType(InputType.TYPE_CLASS_NUMBER);
elevationViews[i].setFilters(new InputFilter[]{ new InputFilterMinMax(0, 90)});
elevationViews[i].setTextSize(18);
opacityViews[i].setText(Integer.toString(shadingOpacity[i]));
opacityViews[i].setInputType(InputType.TYPE_CLASS_NUMBER);
opacityViews[i].setFilters(new InputFilter[]{ new InputFilterMinMax(0, 100)});
opacityViews[i].setTextSize(18);
textViews[i].setLayoutParams(p);
elevationViews[i].setLayoutParams(p);
opacityViews[i].setLayoutParams(p);
container[i].addView(textViews[i]);
container[i].addView(elevationViews[i]);
container[i].addView(opacityViews[i]);
shading.addView(container[i]);
}
alert.setTitle(getString(R.string.edit_location_title));
alert.setView(dialogView);
EditText editLatitude = (EditText) dialogView.findViewById(R.id.EditLocation_Lat);
@ -132,15 +193,22 @@ public class ManageLocationsActivity extends NavigationActivity {
editCity.setText(city.getCityName());
editLatitude.setText(Float.toString(city.getLatitude()));
editLatitude.setFilters(new InputFilter[]{ new InputFilterMinMax(-90, 90)});
editLongitude.setText(Float.toString(city.getLongitude()));
editLongitude.setFilters(new InputFilter[]{ new InputFilterMinMax(-180, 180)});
editAzimuth.setText(Float.toString(city.getAzimuthAngle()));
editAzimuth.setFilters(new InputFilter[]{ new InputFilterMinMax(0, 360)});
editTilt.setText(Float.toString(city.getTiltAngle()));
editTilt.setFilters(new InputFilter[]{ new InputFilterMinMax(0, 90)});
editCellsMaxPower.setText(Float.toString(city.getCellsMaxPower()));
editCellsArea.setText(Float.toString(city.getCellsArea()));
editCellsEfficiency.setText(Float.toString(city.getCellsEfficiency()));
editCellsEfficiency.setFilters(new InputFilter[]{ new InputFilterMinMax(0, 100)});
editDiffuseEfficiency.setText(Float.toString(city.getDiffuseEfficiency()));
editDiffuseEfficiency.setFilters(new InputFilter[]{ new InputFilterMinMax(0, 100)});
editInverterPowerLimit.setText(Float.toString(city.getInverterPowerLimit()));
editInverterEfficiency.setText(Float.toString(city.getInverterEfficiency()));
editInverterEfficiency.setFilters(new InputFilter[]{ new InputFilterMinMax(0, 100)});
editTilt.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { }
@ -156,6 +224,11 @@ public class ManageLocationsActivity extends NavigationActivity {
});
alert.setPositiveButton(getString(R.string.dialog_edit_change_button), (dialog, whichButton) -> {
for (int i = 0; i < shadingElevation.length ; i++) {
shadingElevation[i]= Integer.parseInt(elevationViews[i].getText().toString().isEmpty() ? "0" : elevationViews[i].getText().toString());
shadingOpacity[i]= Integer.parseInt(opacityViews[i].getText().toString().isEmpty() ? "0" : opacityViews[i].getText().toString());
}
adapter.updateCity(city, String.valueOf(editCity.getText()),
Float.parseFloat(editLatitude.getText().toString().isEmpty() ? "0" : editLatitude.getText().toString()),
Float.parseFloat(editLongitude.getText().toString().isEmpty() ? "0" : editLongitude.getText().toString()),
@ -166,7 +239,9 @@ public class ManageLocationsActivity extends NavigationActivity {
Float.parseFloat(editCellsEfficiency.getText().toString().isEmpty() ? "0" : editCellsEfficiency.getText().toString()),
Float.parseFloat(editDiffuseEfficiency.getText().toString().isEmpty() ? "0" : editDiffuseEfficiency.getText().toString()),
Float.parseFloat(editInverterPowerLimit.getText().toString().isEmpty() ? "0" : editInverterPowerLimit.getText().toString()),
Float.parseFloat(editInverterEfficiency.getText().toString().isEmpty() ? "0" : editInverterEfficiency.getText().toString())
Float.parseFloat(editInverterEfficiency.getText().toString().isEmpty() ? "0" : editInverterEfficiency.getText().toString()),
shadingElevation,
shadingOpacity
);
});
alert.setNegativeButton(getString(R.string.dialog_add_close_button), (dialog, whichButton) -> {
@ -208,4 +283,5 @@ public class ManageLocationsActivity extends NavigationActivity {
selectedCity.getCityName()
);
}
}

View file

@ -24,7 +24,7 @@ public class CityToWatch {
private float tiltAngle;
private int rank;
private int[] shadingElevation = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
private int[] shadingOpacity = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
private int[] shadingOpacity = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
public CityToWatch() {
}

View file

@ -0,0 +1,32 @@
package org.woheller69.weather.ui.Help;
import android.text.InputFilter;
import android.text.Spanned;
public class InputFilterMinMax implements InputFilter {
private int min, max;
public InputFilterMinMax(int min, int max) {
this.min = min;
this.max = max;
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
String oldString = dest.toString();
String insertString = source.toString();
String newString = new StringBuilder(oldString).insert(dstart,insertString).toString();
float input = Float.parseFloat(newString);
if (isInRange(min, max, input))
return null;
else
return "";
}
private boolean isInRange(int a, int b, float c) {
return b > a ? c >= a && c <= b : c >= b && c <= a;
}
}

View file

@ -3,8 +3,11 @@ package org.woheller69.weather.ui.RecycleList;
import android.content.Context;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.SharedPreferences;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -67,12 +70,16 @@ public class CityWeatherAdapter extends RecyclerView.Adapter<CityWeatherAdapter.
// function update 3-hour or 1-hour forecast list
public void updateForecastData(List<HourlyForecast> hourlyForecasts) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
courseDayList = new ArrayList<>();
for (HourlyForecast f : hourlyForecasts) {
if (f.getForecastTime() >= System.currentTimeMillis()) {
if (sp.getBoolean("pref_debug",false)) {
courseDayList.add(f);
} else {
if (f.getForecastTime() >= System.currentTimeMillis()) {
courseDayList.add(f);
}
}
}
notifyDataSetChanged();

View file

@ -98,15 +98,22 @@ public class CourseOfDayAdapter extends RecyclerView.Adapter<CourseOfDayAdapter.
if (sp.getBoolean("pref_debug",false)) {
holder.diffuseRadiation.setVisibility(View.VISIBLE);
holder.directRadiationNormal.setVisibility(View.VISIBLE);
holder.energyCum.setVisibility(View.VISIBLE);
} else {
holder.diffuseRadiation.setVisibility(View.GONE);
holder.directRadiationNormal.setVisibility(View.GONE);
holder.energyCum.setVisibility(View.GONE);
}
holder.time.setText(StringFormatUtils.formatTimeWithoutZone(context, courseOfDayList.get(position).getLocalForecastTime(context)));
holder.directRadiationNormal.setText(StringFormatUtils.formatInt(courseOfDayList.get(position).getDirectRadiationNormal()," W/qm"));
holder.diffuseRadiation.setText(StringFormatUtils.formatInt(courseOfDayList.get(position).getDiffuseRadiation()," W/qm"));
holder.power.setText(StringFormatUtils.formatInt(courseOfDayList.get(position).getPower()," "+ context.getString(R.string.units_Wh)));
float energyCumulated=0;
for (int i=0; i<=position;i++)
energyCumulated+=courseOfDayList.get(i).getPower();
holder.energyCum.setText(StringFormatUtils.formatInt(energyCumulated," "+ context.getString(R.string.units_Wh)));
updateRecyclerViewHeader(); //update header according to date in first visible item on the left
setIcon(courseOfDayList.get(position).getWeatherID(), holder.weather, isDay);
@ -148,7 +155,7 @@ public class CourseOfDayAdapter extends RecyclerView.Adapter<CourseOfDayAdapter.
TextView directRadiationNormal;
TextView diffuseRadiation;
TextView power;
TextView wind_speed;
TextView energyCum;
CourseOfDayViewHolder(View itemView) {
super(itemView);
@ -158,6 +165,7 @@ public class CourseOfDayAdapter extends RecyclerView.Adapter<CourseOfDayAdapter.
directRadiationNormal = itemView.findViewById(R.id.course_of_day_direct);
diffuseRadiation = itemView.findViewById(R.id.course_of_day_diffuse);
power = itemView.findViewById(R.id.course_of_day_power);
energyCum = itemView.findViewById(R.id.course_of_energy_cum);
}
}

View file

@ -114,7 +114,7 @@ public class RecyclerOverviewListAdapter extends RecyclerView.Adapter<ItemViewHo
public CityToWatch getCitytoWatch(int position){
return cities.get(position);
}
public void updateCity(CityToWatch cityToWatch, String cityName, float latitude, float longitude, float azimuth, float tilt, float cellsMaxPower, float cellsArea, float cellsEfficiency, float diffuseEfficiency, float inverterPowerLimit, float inverterEfficiency) {
public void updateCity(CityToWatch cityToWatch, String cityName, float latitude, float longitude, float azimuth, float tilt, float cellsMaxPower, float cellsArea, float cellsEfficiency, float diffuseEfficiency, float inverterPowerLimit, float inverterEfficiency, int[] shadingElevation, int[] shadingOpacity) {
cityToWatch.setCityName(cityName);
cityToWatch.setLatitude(latitude);
cityToWatch.setLongitude(longitude);
@ -126,6 +126,8 @@ public class RecyclerOverviewListAdapter extends RecyclerView.Adapter<ItemViewHo
cityToWatch.setDiffuseEfficiency(diffuseEfficiency);
cityToWatch.setInverterPowerLimit(inverterPowerLimit);
cityToWatch.setInverterEfficiency(inverterEfficiency);
cityToWatch.setShadingElevation(shadingElevation);
cityToWatch.setShadingOpacity(shadingOpacity);
database.updateCityToWatch(cityToWatch);
notifyDataSetChanged();
}

View file

@ -73,7 +73,7 @@ public class OMDataExtractor implements IDataExtractor {
SQLiteHelper dbhelper = SQLiteHelper.getInstance(context);
CityToWatch city = dbhelper.getCityToWatch(cityID);
SolarPowerPlant spp = new SolarPowerPlant(city.getLatitude(), city.getLongitude(), city.getCellsMaxPower(), city.getCellsArea(), city.getCellsEfficiency(),city.getDiffuseEfficiency(), city.getInverterPowerLimit(), city.getInverterEfficiency(), city.getAzimuthAngle(), city.getTiltAngle());
SolarPowerPlant spp = new SolarPowerPlant(city.getLatitude(), city.getLongitude(), city.getCellsMaxPower(), city.getCellsArea(), city.getCellsEfficiency(),city.getDiffuseEfficiency(), city.getInverterPowerLimit(), city.getInverterEfficiency(), city.getAzimuthAngle(), city.getTiltAngle(), city.getShadingElevation(), city.getShadingOpacity());
IApiToDatabaseConversion conversion = new OMToDatabaseConversion();

View file

@ -5,7 +5,7 @@
android:layout_height="wrap_content">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="0dp"
android:paddingLeft="@dimen/activity_horizontal_margin"
@ -121,5 +121,20 @@
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:hint="@string/edit_location_hint_inverter_efficiency"/>
<LinearLayout
android:id="@+id/edit_Location_shading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingTop="10dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/edit_location_shading_heading"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:layout_marginBottom="10dp"/>
</LinearLayout>
</LinearLayout>
</ScrollView>

View file

@ -48,7 +48,16 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="xy W"
android:text="xy Wh"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/colorPrimaryDark" />
<TextView
android:id="@+id/course_of_energy_cum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:text="xy Wh"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/colorPrimaryDark" />

View file

@ -96,7 +96,7 @@
<string name="dialog_OK_button">OK</string>
<string name="dialog_NO_button">Nein</string>
<string name="dialog_Later_button">Vielleicht später</string>
<string name="dialog_StarOnGitHub">Mögen Sie diese App? Bitte vergeben Sie einen Stern auf GitHub oder spendieren Sie dem Entwickler einen Kaffee über PayPal.</string>
<string name="dialog_StarOnGitHub">Mögen Sie diese App? Bitte vergeben Sie einen Stern auf GitHub und spendieren Sie dem Entwickler einen Kaffee über PayPal.</string>
<string name="settings_show_pressure">Luftdruck anzeigen</string>
<string name="settings_GPS_manual">Nur manuell aktualisieren</string>
<string name="settings_interval_quarter">15 min</string>
@ -116,7 +116,7 @@
<string name="settings_forecast_days">Anzahl der prognostizierten Tage</string>
<string name="edit_location_hint_latitude">Breitengrad [°]</string>
<string name="edit_location_hint_longitude">Längengrad [°]</string>
<string name="edit_location_hint_azimuth">Azimuth [°]</string>
<string name="edit_location_hint_azimuth">Azimut [°]</string>
<string name="edit_location_hint_tilt">Neigung [°]</string>
<string name="edit_location_hint_cells_max_power">Maximalleistung Zelle [W]</string>
<string name="edit_location_hint_cells_efficiency">Wirkungsgrad Zelle [%]</string>
@ -126,5 +126,9 @@
<string name="edit_location_hint_inverter_efficiency">Effizienz Wechselrichter [%]</string>
<string name="units_Wh">Wh</string>
<string name="edit_location_title">Ort bearbeiten</string>
<string name="edit_location_shading_azimuth_heading">Azimut Bereich [°]</string>
<string name="edit_location_shading_solar_elevation_heading">Min. Elevation der Sonne [°]</string>
<string name="edit_location_shading_opacity_heading">Abschattung unterhalb dieser Elevation [%]</string>
<string name="edit_location_shading_heading">Abschattung</string>
</resources>

View file

@ -104,7 +104,7 @@
<string name="dialog_OK_button">OK</string>
<string name="dialog_NO_button">No</string>
<string name="dialog_Later_button">Maybe later</string>
<string name="dialog_StarOnGitHub">Do you like this app? Please give a star on GitHub or buy the developer a coffee via PayPal.</string>
<string name="dialog_StarOnGitHub">Do you like this app? Please give a star on GitHub and buy the developer a coffee via PayPal.</string>
<string name="settings_show_pressure">Show air pressure</string>
<string name="action_position" translatable="false">Update Location</string>
<string name="settings_GPS_manual">Manual update only</string>
@ -128,4 +128,8 @@
<string name="edit_location_hint_inverter_efficiency">Inverter efficiency [%]</string>
<string name="units_Wh">Wh</string>
<string name="edit_location_title">Edit location</string>
<string name="edit_location_shading_azimuth_heading">Azimuth range [°]</string>
<string name="edit_location_shading_solar_elevation_heading">Min. solar elevation [°]</string>
<string name="edit_location_shading_opacity_heading">Shading below this elevation [%]</string>
<string name="edit_location_shading_heading">Shading</string>
</resources>